package org.owasp.webgoat.lessons; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; 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.BR; import org.apache.ecs.html.HR; import org.apache.ecs.html.TD; import org.apache.ecs.html.TR; import org.apache.ecs.html.Table; import org.owasp.webgoat.session.ECSFactory; import org.owasp.webgoat.session.WebSession; /** * Copyright (c) 2002 Free Software Foundation developed under the custody of the Open Web * Application Security Project (http://www.owasp.org) This software package org.owasp.webgoat.is published by OWASP * under the GPL. You should read and accept the LICENSE before you use, modify and/or redistribute * this software. * * @author Jeff Williams Aspect Security * @created October 28, 2003 */ public class PathBasedAccessControl extends LessonAdapter { private final static String FILE = "File"; /** * Description of the Method * * @param s Description of the Parameter * @return Description of the Return Value */ protected Element createContent( WebSession s ) { ElementContainer ec = new ElementContainer(); try { String dir = s.getContext().getRealPath( "/lesson_plans" ); File d = new File( dir ); Table t = new Table().setCellSpacing( 0 ).setCellPadding( 2 ).setWidth("90%").setAlign("center"); if ( s.isColor() ) { t.setBorder( 1 ); } String[] list = d.list(); String listing = "

Current Directory is: " + Encoding.urlDecode( dir ) + "

Choose the file to view:

"; TR tr = new TR(); tr.addElement(new TD().setColSpan(2).addElement( new StringElement(listing) )); t.addElement(tr); tr = new TR(); tr.addElement( new TD().setWidth("35%").addElement( ECSFactory.makePulldown( FILE, list, "", 15 ))); tr.addElement( new TD().addElement( ECSFactory.makeButton( "View File" ))); t.addElement(tr); ec.addElement( t ); // FIXME: would be cool to allow encodings here -- hex, percent, url, etc... String file = s.getParser().getRawParameter( FILE, "" ); // defuse file searching boolean illegalCommand = s.isDefuseOSCommands(); if ( s.isDefuseOSCommands() ) { // allow them to look at any file in the webgoat hierachy. Don't allow them // to look about the webgoat root, except to see the LICENSE file if( upDirCount( file ) == 3 && !file.endsWith("LICENSE")) { s.setMessage( "Access denied" ); s.setMessage( "It appears that you are on the right track. " + "Commands that may compromise the operating system have been disabled. " + "You are only allowed to see one file in this directory. ");; } else if ( upDirCount( file ) > 3 ) { s.setMessage( "Access denied" ); s.setMessage( "It appears that you are on the right track. " + "Commands that may compromise the operating system have been disabled. " + "You are only allowed to see files in the webgoat directory. "); } else { illegalCommand = false; } } // Using the URI supports encoding of the data. // We could force the user to use encoded '/'s == %2f to make the lesson more difficult. // We url Encode our dir name to avoid problems with special characters in our own path. //File f = new File( new URI("file:///" + Encoding.urlEncode(dir).replaceAll("\\\\","/") + "/" + file.replaceAll("\\\\","/")) ); File f = new File( (dir + "\\" + file).replaceAll("\\\\","/")); if( s.isDebug() ) { s.setMessage("File: " + file ); s.setMessage("Dir: " + dir ); //s.setMessage("File URI: " + "file:///" + (Encoding.urlEncode(dir) + "\\" + Encoding.urlEncode(file)).replaceAll("\\\\","/")); s.setMessage(" - isFile(): " + f.isFile() ); s.setMessage(" - exists(): " + f.exists() ); } if ( !illegalCommand ) { if ( f.isFile() && f.exists() ) { // Don't set completion if they are listing files in the // directory listing we gave them. if ( upDirCount( file ) >= 1 ) { s.setMessage( "Congratulations! Access to file allowed" ); s.setMessage( " ==> " + Encoding.urlDecode( f.getCanonicalPath() )); makeSuccess( s ); } else { s.setMessage( "File is already in allowed directory - try again!" ); s.setMessage( " ==> " + Encoding.urlDecode( f.getCanonicalPath() )); } } else if ( file != null && file.length() != 0 ) { s.setMessage( "Access to file/directory \"" + Encoding.urlDecode( f.getCanonicalPath() ) + "\" denied" ); } else { // do nothing, probably entry screen } try { // Show them the file // Strip out some of the extra html from the "help" file ec.addElement( new BR() ); ec.addElement( new BR() ); ec.addElement( new HR().setWidth("100%") ); ec.addElement( "Viewing file: " + f.getCanonicalPath() ); ec.addElement( new HR().setWidth("100%") ); if ( f.length() > 80000 ) { throw new Exception("File is too large"); } String fileData= getFileText( new BufferedReader( new FileReader( f ) ), false ); if ( fileData.indexOf(0x00) != -1) { throw new Exception("File is binary"); } ec.addElement( new StringElement( fileData.replaceAll(System.getProperty("line.separator"),"
") .replaceAll("(?s)","") .replaceAll("

","
") .replaceAll("
\\s
","
") .replaceAll("<\\?", "<") .replaceAll("<(r|u|t)", "<$1"))); } catch (Exception e) { ec.addElement( new BR() ); ec.addElement("The following error occurred while accessing the file: <"); ec.addElement( e.getMessage() ); } } } catch ( Exception e ) { s.setMessage( "Error generating " + this.getClass().getName() ); e.printStackTrace(); } return ( ec ); } private int upDirCount( String fileName ) { int count = 0; int startIndex = fileName.indexOf(".."); while ( startIndex != -1 ) { count++; startIndex = fileName.indexOf("..", startIndex+1); } return count; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ protected Category getDefaultCategory() { return AbstractLesson.A2; } /** * Gets the hints attribute of the AccessControlScreen object * * @return The hints value */ protected List getHints() { List hints = new ArrayList(); hints.add( "Most operating systems allow special characters in the path." ); hints.add( "Use a file explorer to find the tomcat\\webapps\\WebGoat\\lesson_plans directory" ); hints.add( "Try .. in the path" ); hints.add( "Try ..\\..\\..\\LICENSE" ); return hints; } /** * Gets the instructions attribute of the WeakAccessControl object * * @return The instructions value */ public String getInstructions(WebSession s) { String instructions = "The '" + s.getUserName() + "' user has access to all the files in the " + "lesson_plans directory. Try to break the access control mechanism and access a " + "resource that is not in the listed directory. After selecting a file to view, WebGoat " + "will report if access to the file was granted. An interesting file to try and obtain might " + "be a file like tomcat/conf/tomcat-users.xml"; return ( instructions ); } private final static Integer DEFAULT_RANKING = new Integer(120); protected Integer getDefaultRanking() { return DEFAULT_RANKING; } /** * Gets the title attribute of the AccessControlScreen object * * @return The title value */ public String getTitle() { return ( "How to Bypass a Path Based Access Control Scheme" ); } }