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 javax.servlet.http.HttpServletResponse; import org.apache.ecs.*; import org.apache.ecs.html.*; import org.owasp.webgoat.session.ECSFactory; import org.owasp.webgoat.session.WebSession; /*************************************************************************************************** * * * This file is part of WebGoat, an Open Web Application Security Project utility. For details, * please see http://www.owasp.org/ * * Copyright (c) 2002 - 2007 Bruce Mayhew * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program; if * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. * * Getting Source ============== * * Source for this application is maintained at code.google.com, a repository for free software * projects. * * For details, please see http://code.google.com/p/webgoat/ * * @author Sherif Koussa Macadamian Technologies. * @created September 30, 2006 */ public class HttpSplitting extends SequentialLessonAdapter { private final static String LANGUAGE = "language"; private final static String REDIRECT = "fromRedirect"; private static String STAGE = "stage"; private final static IMG MAC_LOGO = new IMG("images/logos/macadamian.gif").setAlt("Macadamian Technologies") .setBorder(0).setHspace(0).setVspace(0); /** * Description of the Method * * @param s * Current WebSession */ public void handleRequest(WebSession s) { // Setting a special action to be able to submit to redirect.jsp Form form = new Form("/WebGoat/lessons/General/redirect.jsp?" + "Screen=" + String.valueOf(getScreenId()) + "&menu=" + getDefaultCategory().getRanking().toString(), Form.POST).setName("form").setEncType(""); form.addElement(createContent(s)); setContent(form); } protected Element doHTTPSplitting(WebSession s) { ElementContainer ec = new ElementContainer(); String lang = null; try { 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", ""); if (lang.length() != 0 && fromRedirect.length() != 0) { // Split by the line separator line.separator is platform independant String lineSep = System.getProperty("line.separator"); String[] arrTokens = lang.toString().toUpperCase().split(lineSep); // Check if the user ended the first request and wrote the second malacious reply if (Arrays.binarySearch(arrTokens, "CONTENT-LENGTH: 0") >= 0 && Arrays.binarySearch(arrTokens, "HTTP/1.1 200 OK") >= 0) { HttpServletResponse res = s.getResponse(); res.setContentType("text/html"); PrintWriter out = new PrintWriter(res.getOutputStream()); String message = lang.substring(lang.indexOf("")); out.print(message); out.flush(); out.close(); 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; if (getLessonTracker(s).getStage() == 1) { ec.addElement(new H3("Stage 1: HTTP Splitting:

")); } else { ec.addElement(new H3("Stage 2: Cache Poisoning:

")); } 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 { s.setMessage("Now that you have successfully performed an HTTP Splitting, now try to poison" + " the victim's cache. 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); } } } } catch (Exception ex) { ec.addElement(new P().addElement(ex.getMessage())); } return ec; } protected Category getDefaultCategory() { return Category.GENERAL; } protected List getHints(WebSession s) { List hints = new ArrayList(); hints.add("Enter a language for the system to search by."); hints.add("Use CR (%0d) and LF (%0a) for a new line in Windows and only LF (%0a) in Linux."); 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("NOTE: THIS HINT IS FOR WINDOWS AND HAS TO BE ALTERED FOR ANOTHER SYSTEM
Try: language=?foobar%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2047%0d%0a%0d%0a<html>Insert undesireable content here</html>"); hints .add("Cache Poisoning starts with including 'Last-Modified' header in the hijacked page and setting it to a future date."); hints .add("NOTE: THIS HINT IS FOR WINDOWS AND HAS TO BE ALTERED FOR ANOTHER SYSTEM
Try language=?foobar%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aLast-Modified:%20Mon,%2027%20Oct%202030%2014:50:18%20GMT%0d%0aContent-Length:%2047%0d%0a%0d%0a<html>Insert undesireable content here</html>"); hints .add("'Last-Modified' header forces the browser to send a 'If-Modified-Since' header. Some cache servers will take the bait and keep serving the hijacked page"); hints .add("NOTE: THIS HINT IS FOR WINDOWS AND HAS TO BE ALTERED FOR ANOTHER SYSTEM
Try to intercept the reply and add HTTP/1.1 304 Not Modified0d%0aDate:%20Mon,%2027%20Oct%202030%2014:50:18%20GMT"); return hints; } private final static Integer DEFAULT_RANKING = new Integer(20); protected Integer getDefaultRanking() { return DEFAULT_RANKING; } /** * Gets the title attribute of the HelloScreen object * * @return The title value */ public String getTitle() { return ("HTTP Splitting"); } public Element getCredits() { return super.getCustomCredits("Created by Sherif Koussa ", MAC_LOGO); } }