Added testcase for SQL injection lesson

This commit is contained in:
Nanne Baars 2017-05-21 16:40:52 +02:00
parent 9f12da1434
commit 129e9deba9
9 changed files with 257 additions and 577 deletions

View File

@ -25,11 +25,10 @@
package org.owasp.webgoat.assignments;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.apache.commons.lang3.StringEscapeUtils;
import org.owasp.webgoat.i18n.PluginMessages;
@AllArgsConstructor
public class AttackResult {
public static class AttackResultBuilder {
@ -89,6 +88,11 @@ public class AttackResult {
@Getter
private String output;
public AttackResult(boolean lessonCompleted, String feedback, String output) {
this.lessonCompleted = lessonCompleted;
this.feedback = StringEscapeUtils.escapeJson(feedback);
this.output = StringEscapeUtils.escapeJson(output);
}
public static AttackResultBuilder builder(PluginMessages messages) {
return new AttackResultBuilder(messages);

View File

@ -2,7 +2,7 @@ package org.owasp.webgoat.plugins;
import org.junit.Before;
import org.owasp.webgoat.i18n.Language;
import org.owasp.webgoat.i18n.Messages;
import org.owasp.webgoat.i18n.PluginMessages;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.embedded.LocalServerPort;
@ -30,7 +30,7 @@ public abstract class LessonTest {
@Autowired
protected WebApplicationContext wac;
@Autowired
protected Messages messages;
protected PluginMessages messages;
@MockBean
protected WebSession webSession;
@MockBean
@ -38,7 +38,8 @@ public abstract class LessonTest {
@Before
public void init() {
when(language.getLocale()).thenReturn(Locale.US);
when(webSession.getUserName()).thenReturn("unit-test");
when(language.getLocale()).thenReturn(Locale.getDefault());
}
}

View File

@ -2,6 +2,7 @@
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.owasp.webgoat.session.DatabaseUtilities;
@ -10,12 +11,10 @@ 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.*;
/***************************************************************************************************
*
*
@ -47,28 +46,27 @@ import java.sql.*;
* @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, HttpServletRequest request) throws IOException {
public
@ResponseBody
AttackResult completed(@RequestParam String account) {
return injectableQuery(account);
}
protected AttackResult injectableQuery(String accountName)
{
try
{
protected AttackResult injectableQuery(String accountName) {
try {
Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
try
{
try {
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first() == true))
{
if ((results != null) && (results.first())) {
ResultSetMetaData resultsMetaData = results.getMetaData();
StringBuffer output = new StringBuffer();
@ -76,42 +74,33 @@ public class SqlInjectionLesson5a extends AssignmentEndpoint {
results.last();
// If they get back more than one user they succeeded
if (results.getRow() >= 6)
{
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
{
} else {
return trackProgress(failed().feedback("sql-injection.5a.no.results").build());
}
} catch (SQLException sqle)
{
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage()).build());
}
} catch (Exception e)
{
e.printStackTrace();
} catch (Exception e) {
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
}
}
public String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException,
SQLException
{
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++)
{
if (results.next()) {
for (int i = 1; i < (numColumns + 1); i++) {
t.append(resultsMetaData.getColumnName(i));
t.append(", ");
}
@ -119,11 +108,9 @@ public class SqlInjectionLesson5a extends AssignmentEndpoint {
t.append("<br />");
results.beforeFirst();
while (results.next())
{
while (results.next()) {
for (int i = 1; i < (numColumns + 1); i++)
{
for (int i = 1; i < (numColumns + 1); i++) {
t.append(results.getString(i));
t.append(", ");
}
@ -131,90 +118,11 @@ public class SqlInjectionLesson5a extends AssignmentEndpoint {
t.append("<br />");
}
}
else
{
} 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;
//
// }
}

View File

@ -1,8 +1,8 @@
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.owasp.webgoat.session.DatabaseUtilities;
@ -16,7 +16,6 @@ import java.io.IOException;
import java.sql.*;
/***************************************************************************************************
*
*
@ -48,177 +47,53 @@ import java.sql.*;
* @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 {
public
@ResponseBody
AttackResult completed(@RequestParam String userid, HttpServletRequest request) throws IOException {
return injectableQuery(userid);
}
protected AttackResult injectableQuery(String accountName)
{
try
{
protected AttackResult injectableQuery(String accountName) {
try {
Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT * FROM user_data WHERE userid = " + accountName;
try
{
try {
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first() == true))
{
if ((results != null) && (results.first() == true)) {
ResultSetMetaData resultsMetaData = results.getMetaData();
StringBuffer output = new StringBuffer();
output.append(writeTable(results, resultsMetaData));
output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData));
results.last();
// If they get back more than one user they succeeded
if (results.getRow() >= 6)
{
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
{
} else {
return trackProgress(failed().feedback("sql-injection.5b.no.results").build());
// output.append(getLabelManager().get("NoResultsMatched"));
}
} catch (SQLException sqle)
{
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage()).build());
}
} catch (Exception e)
{
} 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;
//
// }
}

View File

@ -2,6 +2,7 @@
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.owasp.webgoat.session.DatabaseUtilities;
@ -10,10 +11,10 @@ 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.*;
import static org.owasp.webgoat.plugin.SqlInjectionLesson5a.writeTable;
/***************************************************************************************************
@ -47,30 +48,29 @@ import java.sql.*;
* @created October 28, 2003
*/
@AssignmentPath("/SqlInjection/attack6a")
@AssignmentHints(value = {"SqlStringInjectionHint5", "SqlStringInjectionHint6"})
public class SqlInjectionLesson6a extends AssignmentEndpoint {
@RequestMapping(method = RequestMethod.POST)
public @ResponseBody AttackResult completed(@RequestParam String userid_6a, HttpServletRequest request) throws IOException {
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
{
protected AttackResult injectableQuery(String accountName) {
try {
Connection connection = DatabaseUtilities.getConnection(getWebSession());
String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'";
try
{
try {
Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet results = statement.executeQuery(query);
if ((results != null) && (results.first() == true))
{
if ((results != null) && (results.first())) {
ResultSetMetaData resultsMetaData = results.getMetaData();
StringBuffer output = new StringBuffer();
@ -78,146 +78,22 @@ public class SqlInjectionLesson6a extends AssignmentEndpoint {
results.last();
// If they get back more than one user they succeeded
if (results.getRow() >= 5)
{
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
{
} else {
return trackProgress(failed().feedback("sql-injection.6a.no.results").build());
}
} catch (SQLException sqle)
{
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage()).build());
}
} catch (Exception e)
{
} 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;
//
// }
}

View File

@ -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,30 +66,19 @@
</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"
@ -133,18 +93,11 @@
</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"
@ -159,54 +112,36 @@
</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>

View File

@ -6,7 +6,8 @@ SqlStringInjectionHint1=The application is taking your input and inserting it at
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=Try adding a union to the query, the number of columns should match.
SqlStringInjectionHint6=Try entering [ Smith' union select userid,user_name, password,cookie,cookie, cookie,userid from user_system_data -- ].
sql-injection.5a.success=You have succeed: {0}
sql-injection.5a.no.results=No results matched. Try Again.

View File

@ -0,0 +1,81 @@
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.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''")));
}
}

View File

@ -3,7 +3,6 @@ package org.owasp.webgoat.plugin;
import com.beust.jcommander.internal.Lists;
import com.google.common.base.Joiner;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringEscapeUtils;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
@ -83,7 +82,7 @@ public class BlindSendFileAssignment extends AssignmentEndpoint {
Comment comment = comments.parseXml(commentStr);
comments.addComment(comment, false);
} catch (Exception e) {
error = StringEscapeUtils.escapeJson(e.toString());
error = e.toString();
}
File logFile = new File(webGoatHomeDirectory, "/XXE/log" + webSession.getUserName() + ".txt");