271 lines
10 KiB
Java
271 lines
10 KiB
Java
package org.owasp.webgoat.lessons;
|
|
|
|
import java.sql.Connection;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.Statement;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import org.apache.ecs.Element;
|
|
import org.apache.ecs.ElementContainer;
|
|
import org.apache.ecs.StringElement;
|
|
import org.apache.ecs.html.Input;
|
|
import org.apache.ecs.html.P;
|
|
import org.owasp.webgoat.session.DatabaseUtilities;
|
|
import org.owasp.webgoat.session.ECSFactory;
|
|
import org.owasp.webgoat.session.WebSession;
|
|
|
|
|
|
/**
|
|
* Copyright (c) 2005 Free Software Foundation developed under the custody of the Open Web
|
|
* Application Security Project (http://www.owasp.org) This software package is published by OWASP
|
|
* under the GPL. You should read and accept the LICENSE before you use, modify and/or redistribute
|
|
* this software.
|
|
*
|
|
* @author Chuck Willis <a href="http://www.securityfoundry.com">Chuck's web site</a> (this lesson is heavily based on Jeff Williams' SQL Injection lesson
|
|
* @created January 14, 2005
|
|
*/
|
|
public class BlindSqlInjection extends LessonAdapter
|
|
{
|
|
private final static String ACCT_NUM = "account_number";
|
|
private final static int TARGET_ACCT_NUM = 15613;
|
|
private static Connection connection = null;
|
|
|
|
|
|
/**
|
|
* Description of the Method
|
|
*
|
|
* @param s Description of the Parameter
|
|
* @return Description of the Return Value
|
|
*/
|
|
protected Element createContent( WebSession s )
|
|
{
|
|
ElementContainer ec = new ElementContainer();
|
|
|
|
try
|
|
{
|
|
if ( connection == null )
|
|
{
|
|
connection = DatabaseUtilities.makeConnection( s );
|
|
}
|
|
|
|
ec.addElement( new P().addElement( "Enter your Account Number: " ) );
|
|
|
|
String accountNumber = s.getParser().getRawParameter( ACCT_NUM, "101" );
|
|
Input input = new Input( Input.TEXT, ACCT_NUM, accountNumber.toString() );
|
|
ec.addElement( input );
|
|
|
|
Element b = ECSFactory.makeButton( "Go!" );
|
|
ec.addElement( b );
|
|
|
|
String query = "SELECT * FROM user_data WHERE userid = " + accountNumber ;
|
|
String answer_query;
|
|
if(runningOnWindows()) {
|
|
answer_query = "SELECT TOP 1 first_name FROM user_data WHERE userid = " + TARGET_ACCT_NUM;
|
|
} else {
|
|
answer_query = "SELECT first_name FROM user_data WHERE userid = " + TARGET_ACCT_NUM;
|
|
}
|
|
|
|
try
|
|
{
|
|
Statement answer_statement = connection.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
|
|
ResultSet answer_results = answer_statement.executeQuery( answer_query );
|
|
answer_results.first();
|
|
if( accountNumber.toString().equals(answer_results.getString(1))) {
|
|
makeSuccess( s );
|
|
} else {
|
|
|
|
Statement statement = connection.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
|
|
ResultSet results = statement.executeQuery( query );
|
|
|
|
if ( ( results != null ) && ( results.first() == true ) )
|
|
{
|
|
ec.addElement( new P().addElement("Account number is valid"));
|
|
} else {
|
|
ec.addElement( new P().addElement("Invalid account number"));
|
|
}
|
|
}
|
|
}
|
|
catch ( SQLException sqle )
|
|
{
|
|
ec.addElement( new P().addElement("An error occurred, please try again."));
|
|
}
|
|
}
|
|
catch ( Exception e )
|
|
{
|
|
s.setMessage( "Error generating " + this.getClass().getName() );
|
|
e.printStackTrace();
|
|
}
|
|
|
|
return ( ec );
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Gets the category attribute of the SqlInjection object
|
|
*
|
|
* @return The category value
|
|
*/
|
|
public Category getCategory()
|
|
{
|
|
return AbstractLesson.A6;
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the credits attribute of the AbstractLesson object
|
|
*
|
|
* @return The credits value
|
|
*/
|
|
public Element getCredits()
|
|
{
|
|
return new StringElement("By Chuck Willis (edited 14 Dec 05 - Hints need to updated for non-Windows systems)");
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Determines the OS that WebGoat is running on. Needed because different DB backends
|
|
* are used on the different OSes (Access on Windows, InstantDB on others)
|
|
*
|
|
* @return true if running on Windows, false otherwise
|
|
*/
|
|
private boolean runningOnWindows() {
|
|
String os = System.getProperty("os.name","Windows");
|
|
if ( os.toLowerCase().indexOf("window") != -1 )
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the hints attribute of the DatabaseFieldScreen object
|
|
*
|
|
* @return The hints value
|
|
*/
|
|
protected List getHints()
|
|
{
|
|
List hints = new ArrayList();
|
|
if (runningOnWindows()) {
|
|
hints.add( "Compound SQL statements can be made by joining multiple tests with keywords like AND and OR. " +
|
|
"Create a SQL statement that you can use as a true/false test and then " +
|
|
"select the first character of the target element and do a start narrowing " +
|
|
"down the character using > and <" +
|
|
"<br><br>The backend database is Microsoft Access. Keep that in mind if you research SQL functions " +
|
|
"on the Internet since different databases use some different functions and syntax.");
|
|
hints.add( "This is the code for the query being built and issued by WebGoat:<br><br> " +
|
|
"\"SELECT * FROM user_data WHERE userid = \" + accountNumber " );
|
|
hints.add( "The application is taking your input and inserting it at the end of a pre-formed SQL command. "+
|
|
"You will need to make use of the following SQL functions: " +
|
|
"<br><br>SELECT - query for your target data and get a string "+
|
|
"<br><br>mid(string, start, length) - returns a "
|
|
+ "substring of string starting at the start character and going for length characters "+
|
|
"<br><br>asc(string) will return the ascii value of the first character in string " +
|
|
"<br><br>> and < - once you have a character's value, compare it to a choosen one");
|
|
hints.add( "Example: is the first character of the first_name of userid " + TARGET_ACCT_NUM + " less than 'M' (ascii 77)? " +
|
|
"<br><br>101 AND (asc( mid((SELECT first_name FROM user_data WHERE userid=" + TARGET_ACCT_NUM + ") , 1 , 1) ) < 77 ); " +
|
|
"<br><br>If you get back that account number is valid, then yes. If get back that the number is" +
|
|
"invalid then answer is no.");
|
|
hints.add( "Another example: is the second character of the first_name of userid " + TARGET_ACCT_NUM + " greater than 'm' (ascii 109)? " +
|
|
"<br><br>101 AND (asc( mid((SELECT first_name FROM user_data WHERE userid=" + TARGET_ACCT_NUM + ") , 2 , 1) ) > 109 ); " +
|
|
"<br><br>If you get back that account number is valid, then yes. If get back that the number is " +
|
|
"invalid then answer is no.");
|
|
} else {
|
|
hints.add("Compound SQL statements can be made by joining multiple tests with keywords like AND and OR. " +
|
|
"Create a SQL statement that you can use as a true/false test and then " +
|
|
"select the first character of the target element and do a start narrowing " +
|
|
"down the character using > and <" );
|
|
|
|
hints.add("The database backend is InstantDB. Here is a reference guide : <a href=\"http://www.instantdb.com/doc/syntax.html\" target=\"_blank\">http://www.instantdb.com/doc/syntax.html</a>");
|
|
hints.add( "This is the code for the query being built and issued by WebGoat:<br><br> " +
|
|
"\"SELECT * FROM user_data WHERE userid = \" + accountNumber " );
|
|
hints.add( "THIS HINT IS FOR THE MS ACCESS DB. IT NEEDS TO BE ALTERED FOR THE INSTANTDB BACKEND. <br><br>The application is taking your input and inserting it at the end of a pre-formed SQL command. "+
|
|
"You will need to make use of the following SQL functions: " +
|
|
"<br><br>SELECT - query for your target data and get a string "+
|
|
"<br><br>mid(string, start, length) - returns a "
|
|
+ "substring of string starting at the start character and going for length characters "+
|
|
"<br><br>asc(string) will return the ascii value of the first character in string " +
|
|
"<br><br>> and < - once you have a character's value, compare it to a choosen one");
|
|
hints.add( "THIS HINT IS FOR THE MS ACCESS DB. IT NEEDS TO BE ALTERED FOR THE INSTANTDB BACKEND. <br><br>Example: is the first character of the first_name of userid " + TARGET_ACCT_NUM + " less than 'M' (ascii 77)? " +
|
|
"<br><br>101 AND (asc( mid((SELECT first_name FROM user_data WHERE userid=" + TARGET_ACCT_NUM + ") , 1 , 1) ) < 77 ); " +
|
|
"<br><br>If you get back that account number is valid, then yes. If get back that the number is" +
|
|
"invalid then answer is no.");
|
|
hints.add( "THIS HINT IS FOR THE MS ACCESS DB. IT NEEDS TO BE ALTERED FOR THE INSTANTDB BACKEND. <br><br> example: is the second character of the first_name of userid " + TARGET_ACCT_NUM + " greater than 'm' (ascii 109)? " +
|
|
"<br><br>101 AND (asc( mid((SELECT first_name FROM user_data WHERE userid=" + TARGET_ACCT_NUM + ") , 2 , 1) ) > 109 ); " +
|
|
"<br><br>If you get back that account number is valid, then yes. If get back that the number is " +
|
|
"invalid then answer is no.");
|
|
}
|
|
return hints;
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the instructions attribute of the SqlInjection object
|
|
*
|
|
* @return The instructions value
|
|
*/
|
|
public String getInstructions(WebSession s)
|
|
{
|
|
String instructions = "The form below allows a user to enter an account number and determine if "+
|
|
"it is valid or not. Use this form to develop a true / false test check other entries in the database. "+
|
|
"<br><br>Reference Ascii Values: 'A' = 65 'Z' = 90 'a' = 97 'z' = 122 " +
|
|
"<br><br>The goal is to find the value of "+
|
|
"the first_name in table user_data for userid " + TARGET_ACCT_NUM + ". Put that name in the form to pass the lesson.";
|
|
|
|
return ( instructions );
|
|
}
|
|
|
|
|
|
|
|
|
|
private final static Integer DEFAULT_RANKING = new Integer(70);
|
|
|
|
protected Integer getDefaultRanking()
|
|
{
|
|
return DEFAULT_RANKING;
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the title attribute of the DatabaseFieldScreen object
|
|
*
|
|
* @return The title value
|
|
*/
|
|
public String getTitle()
|
|
{
|
|
return ( "How to Perform Blind SQL Injection" );
|
|
}
|
|
|
|
|
|
/**
|
|
* Constructor for the DatabaseFieldScreen object
|
|
*
|
|
* @param s Description of the Parameter
|
|
*/
|
|
public void handleRequest( WebSession s )
|
|
{
|
|
try
|
|
{
|
|
super.handleRequest( s );
|
|
|
|
if ( connection == null )
|
|
{
|
|
connection = DatabaseUtilities.makeConnection( s );
|
|
}
|
|
}
|
|
catch ( Exception e )
|
|
{
|
|
System.out.println( "Exception caught: " + e );
|
|
e.printStackTrace( System.out );
|
|
}
|
|
}
|
|
}
|
|
|
|
|