diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/HttpSplitting.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/HttpSplitting.java
index a064f77b8..15bfce6eb 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/HttpSplitting.java
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/HttpSplitting.java
@@ -1,6 +1,8 @@
package org.owasp.webgoat.lessons;
import java.io.PrintWriter;
import java.net.URLDecoder;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
import java.util.*;
import org.apache.ecs.*;
@@ -22,6 +24,8 @@ import org.owasp.webgoat.session.WebSession;
public class HttpSplitting extends LessonAdapter {
private final static String LANGUAGE = "language";
+ private final static String REDIRECT = "fromRedirect";
+ private static String STAGE = "stage";
/**
* Description of the Method
@@ -41,35 +45,19 @@ public class HttpSplitting extends LessonAdapter {
setContent(form);
}
- protected Element createContent(WebSession s)
+ protected Element doHTTPSplitting(WebSession s)
{
ElementContainer ec = new ElementContainer();
String lang = null;
try
{
- //add the text
- ec.addElement( new StringElement( "Search by country : " ) );
-
- lang = URLDecoder.decode(s.getParser().getRawParameter( LANGUAGE, "" )) ;
-
- //add the search by field
- Input input = new Input( Input.TEXT, LANGUAGE, lang.toString() );
- ec.addElement( input );
-
- Element b = ECSFactory.makeButton( "Search!" );
-
- ec.addElement( b );
-
- }
- catch (Exception e)
- {
- s.setMessage( "Error generating " + this.getClass().getName() );
- e.printStackTrace();
- }
+ ec.addElement(createAttackEnvironment(s));
+ lang = URLDecoder.decode(s.getParser().getRawParameter( LANGUAGE, "" ), "UTF-8") ;
//Check if we are coming from the redirect page
- String fromRedirect = s.getParser().getStringParameter ( "fromRedirect" , "");
+ String fromRedirect = s.getParser().getStringParameter ( "fromRedirect" , "");
+
if ( lang.length() != 0 && fromRedirect.length() != 0 )
{
//Split by the line separator line.separator is platform independant
@@ -81,26 +69,117 @@ public class HttpSplitting extends LessonAdapter {
if (Arrays.binarySearch(arrTokens, "CONTENT-LENGTH: 0") >= 0 &&
Arrays.binarySearch(arrTokens, "HTTP/1.1 200 OK") >= 0 )
{
- try
- {
- PrintWriter out = new PrintWriter(s.getResponse().getOutputStream());
- out.print(lang.substring(lang.indexOf("HTTP/1.1")));
- out.flush();
- out.close();
-
- //we gotta set it manually here so that we don't throw an exception
- getLessonTracker(s).setCompleted(true);
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- makeSuccess( s );
+ PrintWriter out = new PrintWriter(s.getResponse().getOutputStream());
+ out.print(lang.substring(lang.indexOf("HTTP/1.1")));
+ out.flush();
+ out.close();
+
+ //we gotta set it manually here so that we don't throw an exception
+ getLessonTracker(s).setCompleted(true);
+
+ //makeSuccess( s );
+ getLessonTracker(s).setStage(2);
+
+ StringBuffer msg = new StringBuffer();
+
+ msg.append("Good Job! ");
+ msg.append("This lesson has detected your successfull attack, ");
+ msg.append("time to elevate your attack to a higher level. ");
+ msg.append("Try again and add Last-Modified header, intercept");
+ msg.append("the reply and replace it with a 304 reply.");
+
+ s.setMessage(msg.toString());
+
}
}
+ }
+ catch (Exception e)
+ {
+ s.setMessage( "Error generating " + this.getClass().getName() );
+ e.printStackTrace();
+ }
return ( ec );
}
+ protected Element createContent(WebSession s)
+ {
+ return super.createStagedContent(s);
+ }
+ protected Element doStage1( WebSession s ) throws Exception
+ {
+ return doHTTPSplitting( s );
+ }
+
+ protected Element doStage2( WebSession s ) throws Exception
+ {
+ return doCachePoisining( s);
+ }
+
+ protected Element createAttackEnvironment(WebSession s ) throws Exception
+ {
+ ElementContainer ec = new ElementContainer();
+ String lang = null;
+
+ ec.addElement( new StringElement( "Search by country : " ) );
+
+ lang = URLDecoder.decode(s.getParser().getRawParameter( LANGUAGE, "" ), "UTF-8") ;
+
+ //add the search by field
+ Input input = new Input( Input.TEXT, LANGUAGE, lang.toString() );
+ ec.addElement( input );
+
+ Element b = ECSFactory.makeButton( "Search!" );
+
+ ec.addElement( b );
+
+ return ec;
+ }
+
+ protected Element doCachePoisining( WebSession s ) throws Exception
+ {
+ ElementContainer ec = new ElementContainer();
+
+ try
+ {
+ ec.addElement("Now that you have successfully performed an HTTP Splitting, now try to poison" +
+ " the victim's cache using. Type 'restart' in the input field if you wish to " +
+ " to return to the HTTP Splitting lesson.
");
+ if ( s.getParser().getRawParameter( LANGUAGE, "YOUR_NAME" ).equals("restart"))
+ {
+ getLessonTracker(s).getLessonProperties().setProperty(STAGE,"1");
+ return( doHTTPSplitting(s));
+ }
+
+ ec.addElement(createAttackEnvironment(s));
+ String lang = URLDecoder.decode(s.getParser().getRawParameter( LANGUAGE, "" ), "UTF-8") ;
+ String fromRedirect = s.getParser().getStringParameter ( REDIRECT , "");
+
+ if ( lang.length() != 0 && fromRedirect.length() != 0 )
+ {
+ String lineSep = System.getProperty("line.separator");
+ String dateStr = lang.substring(lang.indexOf("Last-Modified:") + "Last-Modified:".length(),
+ lang.indexOf(lineSep, lang.indexOf("Last-Modified:") ));
+ if (dateStr.length() != 0 )
+ {
+ Calendar cal = Calendar.getInstance();
+
+ DateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
+
+ if (sdf.parse(dateStr.trim()).after(cal.getTime()))
+ {
+ makeSuccess(s);
+ getLessonTracker(s).setStage(2);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ ec.addElement( new P().addElement( ex.getMessage() ) );
+ }
+ return ec;
+ }
+
protected Category getDefaultCategory()
{
return AbstractLesson.GENERAL;
@@ -113,7 +192,7 @@ public class HttpSplitting extends LessonAdapter {
hints.add( "Use CR (%0d) and LF (%0a) for a new line" );
hints.add( "The Content-Length: 0 will tell the server that the first request is over." );
hints.add( "A 200 OK message looks like this: HTTP/1.1 200 OK" );
- hints.add( "Try French%0d%0aContent-Length: 0%0d%0aHTTP/1.1 200 OK" );
+ hints.add( "Try language=?foobar%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2019%0d%0a%0d%0ahahahahaha" );
return hints;
}
diff --git a/ webgoat/main/project/WebContent/lesson_plans/HttpSplitting.html b/ webgoat/main/project/WebContent/lesson_plans/HttpSplitting.html
index 46caba040..fd29eac68 100644
--- a/ webgoat/main/project/WebContent/lesson_plans/HttpSplitting.html
+++ b/ webgoat/main/project/WebContent/lesson_plans/HttpSplitting.html
@@ -13,7 +13,18 @@ The attacker passes malacious code to the web server together with normal input.
A victim application will not be checking for CR (carriage return, also given by %0d or \r)
and LF (line feed, also given by %0a or \n)characters. These characters not only give attackers control
of the remaining headers and body of the response the application intends to send,
-but also allows them to create additional responses entirely under their control
+but also allows them to create additional responses entirely under their control.
+The effect of an HTTP Splitting attack is maximized when accompanied with a Cache Poisining. The goal of
+Cache Poisining attack is to poison the cache of the victim by fooling the cache to believe that the page
+hijacked using the HTTP splitting is a good one and it is indeed the server's copy.
+The attack happens using the HTTP Splitting attack plus adding the Last-Modified: header and setting it
+to a future date. This will force the browser to send If-Modified-Since request header, which gives the attacker
+the chance to intercept the server's reply and replace it with a '304 Not Modified' reply. A sample of a 304 response is:
+HTTP/1.1 304 Not Modified
+Date: Fri, 30 Dec 2005 17:32:47 GMT
+
+
+
General Goal(s):
@@ -22,4 +33,5 @@ but also allows them to create additional responses entirely under their control * You should be able to use the CR (%0d) and LF (%0a) to exploit the attack.