package org.owasp.webgoat.lessons; 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 - 20014 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 https://github.com/WebGoat/WebGoat, a repository for free software * projects. * * For details, please see http://webgoat.github.io * * @author Sherif Koussa <a href="http://www.softwaresecured.com">Software Secured</a> * @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"; public final static A MAC_LOGO = new A().setHref("http://www.softwaresecured.com").addElement(new IMG("images/logos/softwaresecured.gif").setAlt("Software Secured").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(s.getRequest().getContextPath() + "/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) { String[] arrTokens = lang.toString().toUpperCase().split("\r\n"); // Check if the user ended the first request and wrote the second malicious reply if (arrTokens.length > 1) { HttpServletResponse res = s.getResponse(); res.setContentType("text/html"); StringBuffer msg = new StringBuffer(); msg.append("Good Job! "); msg.append("This lesson has detected your successful 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()); getLessonTracker(s).setStage(2); //makeSuccess(s); } } } 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:<br><br>")); } else { ec.addElement(new H3("Stage 2: Cache Poisoning:<br><br>")); } 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.<br><br>"); 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 = "\r\n"; 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<String> getHints(WebSession s) { List<String> hints = new ArrayList<String>(); 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 <br/> Try: foobar%0D%0AContent-Length%3A%200%0D%0A%0D%0AHTTP%2F1.1%20200%20OK%0D%0AContent-Type%3A%20text%2Fhtml%0D%0AContent-Length%3A%2047%0D%0A%0D%0A%3Chtml%3EHacked!%3C%2Fhtml%3E <br/>For insight into what this does, use the PHP charset encoder to decode it."); 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 <br/>Try foobar%0D%0AContent-Length%3A%200%0D%0A%0D%0AHTTP%2F1.1%20200%20OK%0D%0AContent-Type%3A%20text%2Fhtml%0D%0ALast-Modified%3A%20Mon%2C%2027%20Oct%202080%2014%3A50%3A18%20GMT%0D%0AContent-Length%3A%2047%0D%0A%0D%0A%3Chtml%3EHacked%20J%3C%2Fhtml%3E"); 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 <br/>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); } }