Change DBSQLInjection lesson to count the matched rows

This is an improvement over expecting the stored proc
to throw an exception, and is more portable


git-svn-id: http://webgoat.googlecode.com/svn/trunk@238 4033779f-a91e-0410-96ef-6bf7bf53c507
This commit is contained in:
rogan.dawes 2008-01-10 10:13:13 +00:00
parent 0149a699a3
commit cb2a3784b6
5 changed files with 68 additions and 52 deletions

View File

@ -251,7 +251,9 @@ public class DBCrossSiteScripting extends GoatHillsFinancial
@Override @Override
protected boolean getDefaultHidden() { protected boolean getDefaultHidden() {
return ! getWebgoatContext().getDatabaseDriver().contains("oracle"); String driver = getWebgoatContext().getDatabaseDriver();
boolean hidden = ! (driver.contains("oracle") || driver.contains("jtds"));
return hidden;
} }
} }

View File

@ -252,8 +252,9 @@ public class DBSQLInjection extends GoatHillsFinancial
@Override @Override
protected boolean getDefaultHidden() { protected boolean getDefaultHidden() {
return ! getWebgoatContext().getDatabaseDriver().contains("oracle"); String driver = getWebgoatContext().getDatabaseDriver();
boolean hidden = ! (driver.contains("oracle") || driver.contains("jtds"));
return hidden;
} }
} }

View File

@ -4,6 +4,7 @@ import java.sql.CallableStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Types;
import java.util.List; import java.util.List;
import java.util.Vector; import java.util.Vector;
@ -132,52 +133,61 @@ public class Login extends DefaultLessonAction
public boolean login(WebSession s, String userId, String password) public boolean login(WebSession s, String userId, String password)
{ {
System.out.println("Using \"" + password + "\"");
boolean authenticated = false; boolean authenticated = false;
try try
{ {
String call = "{ CALL EMPLOYEE_LOGIN(?,?) }"; String call = "{ ? = call EMPLOYEE_LOGIN(?,?) }"; // NB: "call", not "CALL"! Doh!
try try
{ {
CallableStatement statement = WebSession.getConnection(s) CallableStatement statement = WebSession.getConnection(s)
.prepareCall(call, ResultSet.TYPE_SCROLL_INSENSITIVE, .prepareCall(call, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY); ResultSet.CONCUR_READ_ONLY);
statement.setInt(1, Integer.parseInt(userId)); statement.registerOutParameter(1, Types.INTEGER);
statement.setString(2, password); statement.setInt(2, Integer.parseInt(userId));
// if this executes successfully, we are authenticated statement.setString(3, password);
statement.execute(); statement.execute();
setSessionAttribute(s, int rows = statement.getInt(1);
getLessonName() + ".isAuthenticated", Boolean.TRUE); if (rows > 0) {
setSessionAttribute(s, getLessonName() + "." setSessionAttribute(s,
+ DBSQLInjection.USER_ID, userId); getLessonName() + ".isAuthenticated", Boolean.TRUE);
authenticated = true; setSessionAttribute(s, getLessonName() + "."
if (DBSQLInjection.STAGE1.equals(getStage(s)) && + DBSQLInjection.USER_ID, userId);
DBSQLInjection.PRIZE_EMPLOYEE_ID == Integer.parseInt(userId)) authenticated = true;
{ if (DBSQLInjection.STAGE1.equals(getStage(s)) &&
setStageComplete(s, DBSQLInjection.STAGE1); DBSQLInjection.PRIZE_EMPLOYEE_ID == Integer.parseInt(userId))
} {
setStageComplete(s, DBSQLInjection.STAGE1);
}
} else {
if (DBSQLInjection.STAGE2.equals(getStage(s)))
{
try
{
String call2 = "{ ? = call EMPLOYEE_LOGIN_BACKUP(?,?) }";
statement = WebSession.getConnection(s)
.prepareCall(call2, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
statement.registerOutParameter(1, Types.INTEGER);
statement.setInt(2, Integer.parseInt(userId));
statement.setString(3, password);
statement.execute();
rows = statement.getInt(1);
if (rows > 0)
setStageComplete(s, DBSQLInjection.STAGE2);
}
catch (SQLException sqle2){}
}
}
} }
catch (SQLException sqle) catch (SQLException sqle)
{ {
s.setMessage("Error logging in: " + sqle.getLocalizedMessage()); s.setMessage("Error logging in: " + sqle.getLocalizedMessage());
sqle.printStackTrace(); sqle.printStackTrace();
if (DBSQLInjection.STAGE2.equals(getStage(s)))
{
try
{
String call2 = "{ CALL EMPLOYEE_LOGIN_BACKUP(?,?) }";
CallableStatement statement = WebSession.getConnection(s)
.prepareCall(call2, ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
statement.setInt(1, Integer.parseInt(userId));
statement.setString(2, password);
statement.execute();
setStageComplete(s, DBSQLInjection.STAGE2);
}
catch (SQLException sqle2){}
}
} }
} }
catch (Exception e) catch (Exception e)

View File

@ -2,27 +2,28 @@ package org.owasp.webgoat.lessons.instructor.DBSQLInjection;
/* /*
* The solution is to choose Neville's userid, and enter a password like: * The solution is to choose Neville's userid, and enter a password like:
* ' OR userid=112 OR password=' * ' OR '1'='1
* Modify the Stored procedure LOGIN_EMPLOYEE to use fixed statements or bind variables * Modify the Stored procedure LOGIN_EMPLOYEE to use fixed statements or bind variables
* *
* *
CREATE OR REPLACE PROCEDURE EMPLOYEE_LOGIN(v_id NUMBER, v_password VARCHAR) AS CREATE OR REPLACE FUNCTION WEBGOAT_guest.EMPLOYEE_LOGIN(v_id NUMBER, v_password VARCHAR) RETURN NUMBER AS
v_userid NUMBER; cnt NUMBER;
BEGIN BEGIN
SELECT USERID INTO v_userid FROM EMPLOYEE SELECT COUNT(*) INTO cnt FROM EMPLOYEE
WHERE USERID = v_id WHERE USERID = v_id
AND PASSWORD = v_password; AND PASSWORD = v_password;
RETURN cnt;
END; END;
/ /
* OR * OR
CREATE OR REPLACE PROCEDURE EMPLOYEE_LOGIN(v_id NUMBER, v_password VARCHAR) AS CREATE OR REPLACE FUNCTION WEBGOAT_guest.EMPLOYEE_LOGIN(v_id NUMBER, v_password VARCHAR) RETURN NUMBER AS
stmt VARCHAR(1000); stmt VARCHAR(32767); cnt NUMBER;
v_userid NUMBER;
BEGIN BEGIN
stmt := 'SELECT USERID FROM EMPLOYEE WHERE USERID = :1 AND PASSWORD = :2'; stmt := 'SELECT COUNT (*) FROM EMPLOYEE WHERE USERID = :1 AND PASSWORD = :2';
EXECUTE IMMEDIATE stmt INTO v_userid USING v_id, v_password; EXECUTE IMMEDIATE stmt INTO cnt USING v_id, v_password;
RETURN cnt;
END; END;
/ /

View File

@ -24,19 +24,21 @@ CREATE TABLE WEBGOAT_guest.EMPLOYEE (
); );
CREATE OR REPLACE PROCEDURE WEBGOAT_guest.EMPLOYEE_LOGIN(v_id NUMBER, v_password VARCHAR) AS CREATE OR REPLACE FUNCTION WEBGOAT_guest.EMPLOYEE_LOGIN(v_id NUMBER, v_password VARCHAR) RETURN NUMBER AS
stmt VARCHAR(32767);v_userid NUMBER; stmt VARCHAR(32767);cnt NUMBER;
BEGIN BEGIN
stmt := 'SELECT USERID FROM EMPLOYEE WHERE USERID = ' || v_id || ' AND PASSWORD = ''' || v_password || ''''; stmt := 'SELECT COUNT (*) FROM EMPLOYEE WHERE USERID = ' || v_id || ' AND PASSWORD = ''' || v_password || '''';
EXECUTE IMMEDIATE stmt INTO v_userid; EXECUTE IMMEDIATE stmt INTO cnt;
RETURN cnt;
END; END;
/ /
CREATE OR REPLACE PROCEDURE WEBGOAT_guest.EMPLOYEE_LOGIN_BACKUP(v_id NUMBER, v_password VARCHAR) AS CREATE OR REPLACE FUNCTION WEBGOAT_guest.EMPLOYEE_LOGIN_BACKUP(v_id NUMBER, v_password VARCHAR) RETURN NUMBER AS
stmt VARCHAR(32767);v_userid NUMBER; stmt VARCHAR(32767);cnt NUMBER;
BEGIN BEGIN
stmt := 'SELECT USERID FROM EMPLOYEE WHERE USERID = ' || v_id || ' AND PASSWORD = ''' || v_password || ''''; stmt := 'SELECT COUNT (*) FROM EMPLOYEE WHERE USERID = ' || v_id || ' AND PASSWORD = ''' || v_password || '''';
EXECUTE IMMEDIATE stmt INTO v_userid; EXECUTE IMMEDIATE stmt INTO cnt;
RETURN cnt;
END; END;
/ /