few cleanup items, added least privilege
This commit is contained in:
parent
f091e21c60
commit
507a4cfbdb
@ -59,7 +59,6 @@ public class SqlInjectionLesson6b extends Assignment {
|
|||||||
} else {
|
} else {
|
||||||
return trackProgress(AttackResult.failed("You are close, try again"));
|
return trackProgress(AttackResult.failed("You are close, try again"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -97,9 +96,6 @@ public class SqlInjectionLesson6b extends Assignment {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
System.out.println("Password: " + password);
|
|
||||||
return (password);
|
return (password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -203,54 +203,11 @@
|
|||||||
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
<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="lesson-page-wrapper">
|
||||||
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
<!-- reuse this lesson-page-wrapper block for each 'page' of content in your lesson -->
|
||||||
<!-- include content here. Content will be presented via asciidocs files,
|
<!-- 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 -->
|
which you put in src/main/resources/plugin/lessonplans/{lang}/{fileName}.adoc -->
|
||||||
<!--
|
<div class="adoc-content" th:replace="doc:SqlInjection_content13.adoc"></div>
|
||||||
<div class="adoc-content" th:replace="doc:HttpBasics_content2.adoc"></div>
|
|
||||||
-->
|
|
||||||
<div class="attack-container">
|
|
||||||
<!-- using attack-form class on your form, will allow your request to be ajaxified and stay within the display framework for webgoat -->
|
|
||||||
<div id="lessonContent">
|
|
||||||
<!-- 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/attack1"
|
|
||||||
enctype="application/json;charset=UTF-8">
|
|
||||||
<script>
|
|
||||||
// sample custom javascript in the recommended way ...
|
|
||||||
// a namespace has been assigned for it, but you can roll your own if you prefer
|
|
||||||
webgoat.customjs.assignRandomVal = function () {
|
|
||||||
var x = Math.floor((Math.random() * 100) + 1);
|
|
||||||
document.getElementById("magic_num").value = x;
|
|
||||||
};
|
|
||||||
webgoat.customjs.assignRandomVal();
|
|
||||||
</script>
|
|
||||||
<input type="hidden" name="magic_num" id="magic_num" value="foo" />
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td>Was the HTTP command a POST or a GET:</td>
|
|
||||||
<td><input name="answer" value="" type="TEXT" /></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>What is the magic number:</td>
|
|
||||||
<td><input name="magic_answer" value="" type="TEXT" /><input
|
|
||||||
name="SUBMIT" value="Go!" type="SUBMIT" /></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<!-- 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>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -1,35 +1,35 @@
|
|||||||
== Parameterized Queries – Java Example
|
== Parameterized Queries – Java Example
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
// Parser returns only valid string data
|
// Parser returns only valid string data
|
||||||
String accountID = getParser().getStringParameter(ACCT_ID, "");
|
String accountID = getParser().getStringParameter(ACCT_ID, "");
|
||||||
String data = null;
|
String data = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Read only database connection
|
// Read only database connection
|
||||||
Statement connection = DatabaseUtilities.getConnection(READ_ONLY);
|
Statement connection = DatabaseUtilities.getConnection(READ_ONLY);
|
||||||
|
|
||||||
// Build a fully qualified query
|
// Build a fully qualified query
|
||||||
String query = "SELECT first_name, last_name, acct_id, balance
|
String query = "SELECT first_name, last_name, acct_id, balance
|
||||||
FROM user_data WHERE acct_id = ?";
|
FROM user_data WHERE acct_id = ?";
|
||||||
PreparedStatement statement = connection.prepareStatement(query);
|
PreparedStatement statement = connection.prepareStatement(query);
|
||||||
statement.setString(1, accountID);
|
statement.setString(1, accountID);
|
||||||
ResultSet results = statement.executeQuery();
|
ResultSet results = statement.executeQuery();
|
||||||
if ((results != null) && (results.first() == true))
|
if ((results != null) && (results.first() == true))
|
||||||
{
|
{
|
||||||
// Only one record should be returned for this query
|
// Only one record should be returned for this query
|
||||||
Results.last();
|
Results.last();
|
||||||
if (results.getRow() <= 2)
|
if (results.getRow() <= 2)
|
||||||
{
|
{
|
||||||
data = processAccount(results);
|
data = processAccount(results);
|
||||||
}
|
}
|
||||||
else { // Handle the error – Database integrity issue }
|
else { // Handle the error – Database integrity issue }
|
||||||
}
|
}
|
||||||
else { // Handle the error – no records found }
|
else { // Handle the error – no records found }
|
||||||
}
|
}
|
||||||
catch (SQLException sqle) { // Log and handle the SQL Exception }
|
catch (SQLException sqle) { // Log and handle the SQL Exception }
|
||||||
catch (Exception e) { // Log and handle the Exception }
|
catch (Exception e) { // Log and handle the Exception }
|
||||||
finally { // Always close connection in finally block
|
finally { // Always close connection in finally block
|
||||||
DatabaseUtilities.closeConnection();
|
DatabaseUtilities.closeConnection();
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
@ -1,22 +1,14 @@
|
|||||||
== Parameterized Queries – .NET
|
== Least Privilege
|
||||||
-------------------------------------------------------
|
|
||||||
public static bool isUsernameValid(string username) {
|
|
||||||
RegEx r = new Regex(“^[A-Za-z0-9]{16}$”);
|
|
||||||
Return r.isMatch(username);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SqlConnection conn is set and opened elsewhere for brevity.
|
=== Connect with a minimum set of privileges
|
||||||
try {
|
* The application should connect to the database with different credentials for every trust distinction
|
||||||
string selectString = “SELECT * FROM user_table WHERE username = @userID”;
|
* Applications rarely need delete rights to a table or database
|
||||||
SqlCommand cmd = new SqlCommand( selectString, conn );
|
|
||||||
if ( isUsernameValid( uid ) ) {
|
=== Database accounts should limit schema access
|
||||||
cmd.Parameters.Add( "@userID", SqlDbType.VarChar, 16 ).Value = uid;
|
|
||||||
SqlDataReader myReader = cmd.ExecuteReader();
|
=== Define database accounts for read and read/write access
|
||||||
if ( myReader ) {
|
|
||||||
// make the user record active in some way.
|
=== Multiple connection pools based on access
|
||||||
myReader.Close();
|
* Use read only access for the authentication query
|
||||||
}
|
* Use read/write access for the data modification queries
|
||||||
} else { // handle invalid input }
|
* Use execute for access to stored procedure calls
|
||||||
}
|
|
||||||
catch (Exception e) { // Handle all exceptions… }
|
|
||||||
-------------------------------------------------------
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
== What is SQL Injection?
|
== What is SQL Injection?
|
||||||
|
|
||||||
=== A SQL injection attack consists of insertion or "injection" of an SQL query via the input data from the client to the application
|
=== A SQL injection attack consists of insertion or "injection" of an malicious data via the SQL query input from the client to the application
|
||||||
|
|
||||||
=== A successful SQL injection exploit can:
|
=== A successful SQL injection exploit can:
|
||||||
* Read and modify sensitive data from the database
|
* Read and modify sensitive data from the database
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
==== Potential String Injection
|
==== Potential String Injection
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
"select * from users where name = ‘" + userName + "'";
|
"select * from users where name = '" + userName + "'";
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
==== Potential Numeric Injection
|
==== Potential Numeric Injection
|
||||||
@ -14,13 +14,14 @@
|
|||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
=== Attacker supplies unexpected text
|
=== Attacker supplies unexpected text
|
||||||
* userName = [red]#Smith' or '1'='1#
|
* userName = [red]*Smith' or '1'='1*
|
||||||
* userName =[red]#' or 1=1 --#
|
* userName =[red]*' or 1=1 --*
|
||||||
* userID = [red]#1234567 or 1=1#
|
* userID = [red]*1234567 or 1=1*
|
||||||
* UserName = [red]#Smith’;drop table users; truncate audit_log;--#
|
* UserName = [red]*Smith’;drop table users; truncate audit_log;--*
|
||||||
|
|
||||||
=== Application executes query
|
=== Application executes query
|
||||||
* select * from users where name = [red]#'Smith' or '1' = '1'#
|
* select * from users where name = [red]*'Smith' or '1' = '1'*
|
||||||
** select * from users where name = [red]#'Smith' or TRUE#
|
** select * from users where name = [red]*'Smith' or TRUE*
|
||||||
* select * from users where employee_id = 1234567 or 1=1
|
* select * from users where employee_id = 1234567 or 1=1
|
||||||
* *All records are returned from database*
|
|
||||||
|
*All records are returned from database*
|
||||||
|
@ -6,4 +6,5 @@ The query in the code builds a dynamic query as seen in the previous example. T
|
|||||||
"select * from users where name = ‘" + userName + "'";
|
"select * from users where name = ‘" + userName + "'";
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
Using the form below try to retrieve all the users from the users table.
|
Using the form below try to retrieve all the users from the users table. You shouldn't need to know any specific user name to get the complete list, however you can use 'Smith' to see the data for one user.
|
||||||
|
|
||||||
|
@ -6,4 +6,4 @@ The query in the code builds a dynamic query as seen in the previous example. T
|
|||||||
"select * from users where employee_id = " + userID;
|
"select * from users where employee_id = " + userID;
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
|
|
||||||
Using the form below try to retrieve all the users from the users table.
|
Using the form below try to retrieve all the users from the users table. You shouldn't need to know any specific user name to get the complete list, however you can use '101' to see the data for one user.
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
== Parameterized Queries – Java Snippet
|
== Parameterized Queries – Java Snippet
|
||||||
|
[source,java]
|
||||||
-------------------------------------------------------
|
----
|
||||||
public static bool isUsernameValid(string username) {
|
public static bool isUsernameValid(string username) {
|
||||||
RegEx r = new Regex(“^[A-Za-z0-9]{16}$”);
|
RegEx r = new Regex(“^[A-Za-z0-9]{16}$”);
|
||||||
return r.isMatch(username);
|
return r.isMatch(username);
|
||||||
}
|
}
|
||||||
|
|
||||||
// java.sql.Connection conn is set elsewhere for brevity.
|
// java.sql.Connection conn is set elsewhere for brevity.
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
RecordSet rs = null;
|
RecordSet rs = null;
|
||||||
try {
|
try {
|
||||||
pUserName = request.getParameter(“UserName”);
|
pUserName = request.getParameter(“UserName”);
|
||||||
if ( isUsernameValid (pUsername);
|
if ( isUsernameValid (pUsername);
|
||||||
ps = conn.prepareStatement(“SELECT * FROM user_table
|
ps = conn.prepareStatement(“SELECT * FROM user_table
|
||||||
WHERE username = ? ”);
|
WHERE username = ? ”);
|
||||||
ps.setString(1, pUsername);
|
ps.setString(1, pUsername);
|
||||||
rs = ps.execute();
|
rs = ps.execute();
|
||||||
if ( rs.next() ) {
|
if ( rs.next() ) {
|
||||||
// do the work of making the user record active in some way
|
// do the work of making the user record active in some way
|
||||||
} else { // handle invalid input }
|
}
|
||||||
|
} else { // handle invalid input }
|
||||||
}
|
}
|
||||||
catch (…) { // handle all exceptions … }
|
catch (…) { // handle all exceptions … }
|
||||||
-------------------------------------------------------
|
----
|
@ -11,6 +11,5 @@ This lesson describes what is Structured Query Language (SQL) and how it can be
|
|||||||
* The user will demonstrate knowledge on:
|
* The user will demonstrate knowledge on:
|
||||||
** String SQL Injection
|
** String SQL Injection
|
||||||
** Numeric SQL Injection
|
** Numeric SQL Injection
|
||||||
** Blind SQL Injection
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user