diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CSRF.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CSRF.java index 25832dd8d..87c461bdd 100644 --- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CSRF.java +++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CSRF.java @@ -1,77 +1,251 @@ package org.owasp.webgoat.lessons; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +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.A; +import org.apache.ecs.html.B; +import org.apache.ecs.html.H1; +import org.apache.ecs.html.HR; import org.apache.ecs.html.Input; import org.apache.ecs.html.P; import org.apache.ecs.html.TD; import org.apache.ecs.html.TR; import org.apache.ecs.html.Table; import org.apache.ecs.html.TextArea; +import org.owasp.webgoat.session.DatabaseUtilities; import org.owasp.webgoat.session.ECSFactory; import org.owasp.webgoat.session.WebSession; +import org.owasp.webgoat.util.HtmlEncoder; public class CSRF extends LessonAdapter { private final static String MESSAGE = "message"; + private final static int MESSAGE_COL = 3; + private final static String NUMBER = "Num"; + private final static int NUM_COL = 1; + private final static String STANDARD_QUERY = "SELECT * FROM messages"; private final static String TITLE = "title"; + private final static int TITLE_COL = 2; + private static Connection connection = null; + private static int count = 1; + private final static int USER_COL = 4; // Added by Chuck Willis - used to show user who posted message + + /** + * Adds a feature to the Message attribute of the MessageBoardScreen object + * + * @param s The feature to be added to the Message attribute + */ + protected void addMessage( WebSession s ) + { + try + { + String title = HtmlEncoder.encode( s.getParser().getRawParameter( TITLE, "" ) ); + String message = s.getParser().getRawParameter( MESSAGE, "" ); + + if ( connection == null ) + { + connection = DatabaseUtilities.makeConnection( s ); + } + + String query = "INSERT INTO messages VALUES (?, ?, ?, ? )"; + + PreparedStatement statement = connection.prepareStatement( query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY ); + statement.setInt(1, count++); + statement.setString(2, title); + statement.setString(3, message); + statement.setString(4, s.getUserName()); + statement.executeQuery(); + } + catch ( Exception e ) + { + // ignore the empty resultset on the insert. There are a few more SQL Injection errors + // that could be trapped here but we will let them try. One error would be something + // like "Characters found after end of SQL statement." + if ( e.getMessage().indexOf("No ResultSet was produced") == -1 ) + { + s.setMessage( "Could not add message to database" ); + } + } + } @Override protected Element createContent(WebSession s) { ElementContainer ec = new ElementContainer(); - String emailBody = null; - try{ - Table t = new Table( 0 ).setCellSpacing( 0 ).setCellPadding( 0 ).setBorder( 0 ); - TR row1 = new TR(); - TR row2 = new TR(); - row1.addElement( new TD( new StringElement( "Title: " ) ) ); - - Input inputTitle = new Input( Input.TEXT, TITLE, "" ); - row1.addElement( new TD( inputTitle ) ); - - TD item1 = new TD(); - item1.setVAlign( "TOP" ); - item1.addElement( new StringElement( "Message: " ) ); - row2.addElement( item1 ); - - TD item2 = new TD(); - TextArea ta = new TextArea( MESSAGE, 5, 60 ); - item2.addElement( ta ); - row2.addElement( item2 ); - t.addElement( row1 ); - t.addElement( row2 ); - - Element b = ECSFactory.makeButton( "Submit" ); - ec = new ElementContainer(); - ec.addElement( t ); - ec.addElement( new P().addElement( b ) ); - - emailBody = new String( s.getParser().getRawParameter( MESSAGE, "" ) ); - - } - catch (Exception e) - { - s.setMessage( "Error generating " + this.getClass().getName() ); - e.printStackTrace(); - } - - if (emailBody.length() != 0 && - emailBody.indexOf( "=0 && - emailBody.indexOf( "src=") > 0 && - emailBody.indexOf( "height=\"1\"" ) > 0 && - emailBody.indexOf( "width=\"1\"" ) > 0) - { - makeSuccess( s ); - } + addMessage( s ); + ec.addElement( makeInput( s ) ); + ec.addElement( new HR() ); + ec.addElement( makeCurrent( s ) ); + ec.addElement( new HR() ); + ec.addElement( makeList( s ) ); return ec; } + /** + * Description of the Method + * + * @param s Description of the Parameter + * @return Description of the Return Value + */ + protected Element makeInput( WebSession s ) + { + Table t = new Table( 0 ).setCellSpacing( 0 ).setCellPadding( 0 ).setBorder( 0 ); + TR row1 = new TR(); + TR row2 = new TR(); + row1.addElement( new TD( new StringElement( "Title: " ) ) ); + + Input inputTitle = new Input( Input.TEXT, TITLE, "" ); + row1.addElement( new TD( inputTitle ) ); + + TD item1 = new TD(); + item1.setVAlign( "TOP" ); + item1.addElement( new StringElement( "Message: " ) ); + row2.addElement( item1 ); + + TD item2 = new TD(); + TextArea ta = new TextArea( MESSAGE, 5, 60 ); + item2.addElement( ta ); + row2.addElement( item2 ); + t.addElement( row1 ); + t.addElement( row2 ); + + Element b = ECSFactory.makeButton( "Submit" ); + ElementContainer ec = new ElementContainer(); + ec.addElement( t ); + ec.addElement( new P().addElement( b ) ); + + return ( ec ); + } + + /** + * Description of the Method + * + * @param s Description of the Parameter + * @return Description of the Return Value + */ + public static Element makeList( WebSession s ) + { + Table t = new Table( 0 ).setCellSpacing( 0 ).setCellPadding( 0 ).setBorder( 0 ); + + try + { + if ( connection == null ) + { + connection = DatabaseUtilities.makeConnection( s ); + } + + Statement statement = connection.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY ); + + ResultSet results = statement.executeQuery( STANDARD_QUERY + " WHERE user_name LIKE '" + getNameroot( s.getUserName() ) + "%'" ); + + if ( ( results != null ) && ( results.first() == true ) ) + { + results.beforeFirst(); + + for ( int i = 0; results.next(); i++ ) + { + A a = ECSFactory.makeLink( results.getString( TITLE_COL ), NUMBER, results.getInt( NUM_COL ) ); + TD td = new TD().addElement( a ); + TR tr = new TR().addElement( td ); + t.addElement( tr ); + } + } + } + catch ( Exception e ) + { + s.setMessage( "Error while getting message list." ); + } + + ElementContainer ec = new ElementContainer(); + ec.addElement( new H1( "Message List" ) ); + ec.addElement( t ); + + return ( ec ); + } + + /** + * Description of the Method + * + * @param s Description of the Parameter + * @return Description of the Return Value + */ + protected Element makeCurrent( WebSession s ) + { + ElementContainer ec = new ElementContainer(); + + try + { + int messageNum = s.getParser().getIntParameter( NUMBER, 0 ); + + if ( connection == null ) + { + connection = DatabaseUtilities.makeConnection( s ); + } + + + String query = "SELECT * FROM messages WHERE user_name LIKE ? and num = ?"; + PreparedStatement statement = connection.prepareStatement( query, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY ); + statement.setString(1, getNameroot( s.getUserName() ) + "%"); + statement.setInt(2, messageNum); + ResultSet results = statement.executeQuery(); + + if ( ( results != null ) && results.first() ) + { + ec.addElement( new H1( "Message Contents For: " + results.getString( TITLE_COL )) ); + Table t = new Table( 0 ).setCellSpacing( 0 ).setCellPadding( 0 ).setBorder( 0 ); + TR row1 = new TR( new TD( new B(new StringElement( "Title:" )) ) ); + row1.addElement( new TD( new StringElement( results.getString( TITLE_COL ) ) ) ); + t.addElement( row1 ); + + String messageData = results.getString( MESSAGE_COL ); + TR row2 = new TR( new TD( new B(new StringElement( "Message:" )) ) ); + row2.addElement( new TD( new StringElement( messageData ) ) ); + t.addElement( row2 ); + + // Edited by Chuck Willis - added display of the user who posted the message, so that + // if users use a cross site request forgery or XSS to make another user post a message, + // they can see that the message is attributed to that user + + TR row3 = new TR( new TD( new StringElement( "Posted By:" ) ) ); + row3.addElement( new TD( new StringElement( results.getString( USER_COL ) ) ) ); + t.addElement( row3 ); + + ec.addElement( t ); + + // Some sanity checks that the script may be correct + + String transferFunds = s.getParser().getRawParameter("transferFunds" , ""); + if (transferFunds.length() != 0) + { + makeSuccess(s); + } + } + else + { + if ( messageNum != 0 ) + { + ec.addElement( new P().addElement( "Could not find message " + messageNum ) ); + } + } + } + catch ( Exception e ) + { + s.setMessage( "Error generating " + this.getClass().getName() ); + e.printStackTrace(); + } + + return ( ec ); + } + @Override protected Category getDefaultCategory() { return AbstractLesson.A4; @@ -105,4 +279,14 @@ public class CSRF extends LessonAdapter { return ( "How to Perform Cross Site Request Forgery (CSRF)" ); } + private static String getNameroot( String name ) + { + String nameroot = name; + if (nameroot.indexOf('-') != -1) + { + nameroot = nameroot.substring(0, nameroot.indexOf('-')); + } + return nameroot; + } + } diff --git a/ webgoat/main/project/WebContent/images/header/header.jpg b/ webgoat/main/project/WebContent/images/header/header.jpg index 84259aba4..9468a467b 100644 Binary files a/ webgoat/main/project/WebContent/images/header/header.jpg and b/ webgoat/main/project/WebContent/images/header/header.jpg differ