Adding extra lesson for order by clauses
This commit is contained in:
parent
ee912f734b
commit
a484467419
@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.util.FileSystemUtils;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -23,14 +24,6 @@ public class CleanupLocalProgressFiles {
|
|||||||
@PostConstruct
|
@PostConstruct
|
||||||
public void clean() {
|
public void clean() {
|
||||||
File dir = new File(webgoatHome);
|
File dir = new File(webgoatHome);
|
||||||
if (dir.exists()) {
|
FileSystemUtils.deleteRecursively(dir);
|
||||||
File[] progressFiles = dir.listFiles(f -> f.getName().endsWith(".progress"));
|
|
||||||
if (progressFiles != null) {
|
|
||||||
log.info("Removing stored user preferences...");
|
|
||||||
for (File f : progressFiles) {
|
|
||||||
f.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
package org.owasp.webgoat.plugin.advanced;
|
||||||
|
|
||||||
import org.owasp.webgoat.lessons.Category;
|
import org.owasp.webgoat.lessons.Category;
|
||||||
import org.owasp.webgoat.lessons.NewLesson;
|
import org.owasp.webgoat.lessons.NewLesson;
|
@ -1,4 +1,4 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
package org.owasp.webgoat.plugin.advanced;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
@ -1,4 +1,4 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
package org.owasp.webgoat.plugin.introduction;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
@ -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.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
import org.owasp.webgoat.assignments.AssignmentHints;
|
@ -1,4 +1,4 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
package org.owasp.webgoat.plugin.introduction;
|
||||||
|
|
||||||
|
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
@ -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.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||||
@ -14,8 +14,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
|
|
||||||
import static org.owasp.webgoat.plugin.SqlInjectionLesson5a.writeTable;
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************************************
|
/***************************************************************************************************
|
||||||
*
|
*
|
||||||
@ -74,7 +72,7 @@ public class SqlInjectionLesson6a extends AssignmentEndpoint {
|
|||||||
ResultSetMetaData resultsMetaData = results.getMetaData();
|
ResultSetMetaData resultsMetaData = results.getMetaData();
|
||||||
StringBuffer output = new StringBuffer();
|
StringBuffer output = new StringBuffer();
|
||||||
|
|
||||||
output.append(writeTable(results, resultsMetaData));
|
output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData));
|
||||||
results.last();
|
results.last();
|
||||||
|
|
||||||
// If they get back more than one user they succeeded
|
// If they get back more than one user they succeeded
|
@ -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.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
import org.owasp.webgoat.assignments.AssignmentPath;
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package org.owasp.webgoat.plugin;
|
package org.owasp.webgoat.plugin.mitigation;
|
||||||
|
|
||||||
import org.owasp.webgoat.lessons.Category;
|
import org.owasp.webgoat.lessons.Category;
|
||||||
import org.owasp.webgoat.lessons.NewLesson;
|
import org.owasp.webgoat.lessons.NewLesson;
|
@ -27,6 +27,84 @@
|
|||||||
<div class="adoc-content" th:replace="doc:SqlInjection_content12.adoc"></div>
|
<div class="adoc-content" th:replace="doc:SqlInjection_content12.adoc"></div>
|
||||||
</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="lesson-page-wrapper">
|
||||||
<div class="adoc-content" th:replace="doc:SqlInjection_content13.adoc"></div>
|
<div class="adoc-content" th:replace="doc:SqlInjection_content13.adoc"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,6 +9,10 @@ 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.
|
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.
|
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 -- ].
|
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.success=You have succeed: {0}
|
||||||
sql-injection.5a.no.results=No results matched. Try Again.
|
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,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'.
|
@ -1,11 +1,11 @@
|
|||||||
=== Blind SQL Injection
|
== Blind SQL Injection
|
||||||
|
|
||||||
Blind SQL injection is a type of SQL injection attack that asks the database true or false
|
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
|
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
|
application is configured to show generic error messages, but has not mitigated the code that is vulnerable to SQL
|
||||||
injection.
|
injection.
|
||||||
|
|
||||||
==== Difference
|
=== Difference
|
||||||
|
|
||||||
Let's first start with the difference between a normal SQL injection and a blind SQL injection. In a normal
|
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
|
SQL injection the error messages from the database are displayed and gives enough information to find out how
|
||||||
@ -16,7 +16,7 @@ based on a true or false statement. That's why a blind SQL injection is much mor
|
|||||||
There are several different types of blind SQL injections: content based and time based SQL injections.
|
There are several different types of blind SQL injections: content based and time based SQL injections.
|
||||||
|
|
||||||
|
|
||||||
==== Example
|
=== Example
|
||||||
|
|
||||||
In this case we are trying to ask the database a boolean question based on for example a unique id, for 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`
|
suppose we have the following url: `https://my-shop.com?article=4`
|
||||||
|
@ -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.
|
@ -0,0 +1,80 @@
|
|||||||
|
package org.owasp.webgoat.plugin;
|
||||||
|
|
||||||
|
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")));
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@ package org.owasp.webgoat.plugin;
|
|||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.owasp.webgoat.plugin.introduction.SqlInjection;
|
||||||
import org.owasp.webgoat.plugins.LessonTest;
|
import org.owasp.webgoat.plugins.LessonTest;
|
||||||
import org.owasp.webgoat.session.WebgoatContext;
|
import org.owasp.webgoat.session.WebgoatContext;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user