Merge branch 'next' of https://github.com/WebGoat/WebGoat into next
Conflicts: .gitignore
15
.gitignore
vendored
@ -1,5 +1,18 @@
|
||||
/nb-configuration.xml
|
||||
/nbactions.xml
|
||||
/target/
|
||||
/.classpath
|
||||
/.project
|
||||
/.settings/.jsdtscope
|
||||
/.settings/org.eclipse.jdt.core.prefs
|
||||
/.settings/org.eclipse.m2e.core.prefs
|
||||
/.settings/org.eclipse.wst.common.component
|
||||
/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
|
||||
/.settings/org.eclipse.wst.common.project.facet.core.xml
|
||||
/.settings/org.eclipse.wst.jsdt.ui.superType.container
|
||||
/.settings/org.eclipse.wst.jsdt.ui.superType.name
|
||||
/.settings/org.eclipse.wst.validation.prefs
|
||||
/.externalToolBuilders/
|
||||
.project
|
||||
/target
|
||||
.classpath
|
||||
@ -11,5 +24,3 @@ src/main/main.iml
|
||||
*.LOCAL.*.jsp
|
||||
*.REMOTE.*.jsp
|
||||
|
||||
|
||||
|
||||
|
@ -134,8 +134,8 @@ public class HammerHead extends HttpServlet {
|
||||
logger.debug("Response already committed, exiting");
|
||||
return;
|
||||
}
|
||||
|
||||
if ("true".equals(request.getParameter("start"))) {
|
||||
|
||||
if ("true".equals(request.getParameter("start")) || request.getQueryString() == null) {
|
||||
logger.warn("Redirecting to start controller");
|
||||
response.sendRedirect("start.mvc");
|
||||
return;
|
||||
|
49
src/main/java/org/owasp/webgoat/controller/About.java
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package org.owasp.webgoat.controller;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author rlawson
|
||||
*/
|
||||
@Controller
|
||||
public class About {
|
||||
|
||||
final Logger logger = LoggerFactory.getLogger(About.class);
|
||||
private static final String WELCOMED = "welcomed";
|
||||
|
||||
@RequestMapping(value = "about.mvc", method = RequestMethod.GET)
|
||||
public ModelAndView welcome(HttpServletRequest request,
|
||||
@RequestParam(value = "error", required = false) String error,
|
||||
@RequestParam(value = "logout", required = false) String logout) {
|
||||
|
||||
// set the welcome attribute
|
||||
// this is so the attack servlet does not also
|
||||
// send them to the welcome page
|
||||
HttpSession session = request.getSession();
|
||||
if (session.getAttribute(WELCOMED) == null) {
|
||||
session.setAttribute(WELCOMED, "true");
|
||||
}
|
||||
|
||||
//go ahead and send them to webgoat (skip the welcome page)
|
||||
ModelAndView model = new ModelAndView();
|
||||
//model.setViewName("welcome");
|
||||
//model.setViewName("main_new");
|
||||
model.setViewName("about");
|
||||
return model;
|
||||
}
|
||||
|
||||
}
|
@ -19,7 +19,9 @@ import org.apache.ecs.Element;
|
||||
import org.apache.ecs.ElementContainer;
|
||||
import org.apache.ecs.StringElement;
|
||||
import org.apache.ecs.html.Body;
|
||||
import org.apache.ecs.html.Center;
|
||||
import org.apache.ecs.html.Form;
|
||||
import org.apache.ecs.html.H1;
|
||||
import org.apache.ecs.html.Head;
|
||||
import org.apache.ecs.html.Html;
|
||||
import org.apache.ecs.html.IMG;
|
||||
@ -729,11 +731,8 @@ public abstract class AbstractLesson extends Screen implements Comparable<Object
|
||||
*/
|
||||
public void handleRequest(WebSession s) {
|
||||
// call createContent first so messages will go somewhere
|
||||
|
||||
Form form = new Form(getFormAction(), Form.POST).setName("form").setEncType("");
|
||||
|
||||
form.addElement(createContent(s));
|
||||
|
||||
setContent(form);
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ public class CrossSiteScripting extends GoatHillsFinancial
|
||||
{
|
||||
String solutionFileName = null;
|
||||
String stage = getStage(s);
|
||||
solutionFileName = "/lesson_solutions/Lab XSS/Lab " + stage + ".html";
|
||||
solutionFileName = "/lesson_solutions_1/Lab XSS/Lab " + stage + ".html";
|
||||
return solutionFileName;
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,11 @@ package org.owasp.webgoat.lessons;
|
||||
|
||||
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.Input;
|
||||
import org.owasp.webgoat.session.ECSFactory;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
@ -58,6 +60,7 @@ public class HttpBasics extends LessonAdapter {
|
||||
|
||||
StringBuffer person = null;
|
||||
try {
|
||||
ec.addElement(new BR());
|
||||
ec.addElement(new StringElement(WebGoatI18N.get("EnterYourName") + ": "));
|
||||
|
||||
person = new StringBuffer(s.getParser().getStringParameter(PERSON, ""));
|
||||
|
@ -1,7 +1,6 @@
|
||||
|
||||
package org.owasp.webgoat.lessons;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URLDecoder;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
@ -54,7 +53,8 @@ public class HttpSplitting extends SequentialLessonAdapter
|
||||
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
|
||||
|
@ -176,7 +176,7 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
|
||||
{
|
||||
String solutionFileName = null;
|
||||
String stage = getStage(s);
|
||||
solutionFileName = "/lesson_solutions/Lab Access Control/Lab " + stage + ".html";
|
||||
solutionFileName = "/lesson_solutions_1/Lab Access Control/Lab " + stage + ".html";
|
||||
return solutionFileName;
|
||||
}
|
||||
|
||||
|
@ -272,7 +272,7 @@ public class SQLInjection extends GoatHillsFinancial
|
||||
{
|
||||
String solutionFileName = null;
|
||||
String stage = getStage(s);
|
||||
solutionFileName = "/lesson_solutions/Lab SQL Injection/Lab " + stage + ".html";
|
||||
solutionFileName = "/lesson_solutions_1/Lab SQL Injection/Lab " + stage + ".html";
|
||||
return solutionFileName;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
package org.owasp.webgoat.service;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.owasp.webgoat.lessons.AbstractLesson;
|
||||
import org.owasp.webgoat.session.Course;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class LessonTitleService extends BaseService {
|
||||
|
||||
/**
|
||||
* Returns the title for the current attack
|
||||
*
|
||||
* @param session
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "/lessontitle.mvc", produces = "application/html")
|
||||
public @ResponseBody
|
||||
String showPlan(HttpSession session) {
|
||||
WebSession ws = getWebSession(session);
|
||||
return getLessonTitle(ws);
|
||||
}
|
||||
|
||||
private String getLessonTitle(WebSession s) {
|
||||
String title = "";
|
||||
int scr = s.getCurrentScreen();
|
||||
Course course = s.getCourse();
|
||||
|
||||
if (s.isUser() || s.isChallenge()) {
|
||||
AbstractLesson lesson = course.getLesson(s, scr, AbstractLesson.USER_ROLE);
|
||||
title = lesson != null ? lesson.getTitle() : "";
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
}
|
124
src/main/webapp/WEB-INF/pages/about.jsp
Normal file
@ -0,0 +1,124 @@
|
||||
<%@ page contentType="text/html; charset=ISO-8859-1" language="java"
|
||||
errorPage=""%>
|
||||
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="plugins/bootstrap/css/bootstrap.min.css"/>
|
||||
<link rel="stylesheet" href="css/webgoat.css" type="text/css" />
|
||||
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
|
||||
<h1 class="modal-title" id="myModalLabel">About WebGoat</h1>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Thank you for using WebGoat! This program is a demonstration of common web application flaws.
|
||||
The exercises are intended to provide hands on experience with
|
||||
application penetration testing techniques. </p>
|
||||
<p>The WebGoat project is led
|
||||
by Bruce Mayhew. Please send all comments to Bruce at [TODO, session was blowing up here for some reason].</p>
|
||||
|
||||
<div id="team">
|
||||
<table border="0" align="center" class="lessonText">
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<div align="center"><a href="http://www.owasp.org"><img
|
||||
border="0" src="images/logos/owasp.jpg" alt="OWASP Foundation"
|
||||
longdesc="http://www.owasp.org" /></a></div>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<div align="center"><a href="http://www.aspectsecurity.com"><img
|
||||
border="0" src="images/logos/aspect.jpg" alt="Aspect Security"
|
||||
longdesc="http://www.aspectsecurity.com" /></a></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div align="center"><span class="style1">
|
||||
WebGoat Authors </span></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div align="center"><span class="style2">
|
||||
Bruce Mayhew </span></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<div align="center"><span class="style2">
|
||||
Jeff Williams </span></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%">
|
||||
<div align="center"><span class="style1"><br />
|
||||
WebGoat Design Team </span></div>
|
||||
</td>
|
||||
<td width="50%">
|
||||
<div align="center"><span class="style1"><br />
|
||||
V5.4 Lesson Contributers </span></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">
|
||||
<div align="center" class="style2">David Anderson</div>
|
||||
<div align="center" class="style2">Laurence Casey (Graphics)</div>
|
||||
<div align="center" class="style2">Rogan Dawes</div>
|
||||
<div align="center" class="style2">Bruce Mayhew</div>
|
||||
</td>
|
||||
<td valign="top">
|
||||
<div align="center" class="style2">Sherif Koussa</div>
|
||||
<div align="center" class="style2">Yiannis Pavlosoglou</div>
|
||||
<div align="center" class="style2"></div>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td height="25" valign="bottom">
|
||||
<div align="center"><span class="style1">Special Thanks
|
||||
for V5.4</span></div>
|
||||
</td>
|
||||
<td height="25" valign="bottom">
|
||||
<div align="center"><span class="style1">Documentation
|
||||
Contributers</span></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div align="center" class="style2">Brian Ciomei (Multitude of bug fixes)</div>
|
||||
<div align="center" class="style2">To all who have sent comments</div>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<div align="center" class="style2">
|
||||
<a href="http://www.zionsecurity.com/" target="_blank">Erwin Geirnaert</a></div>
|
||||
<div align="center" class="style2">
|
||||
<a href="http://yehg.org/" target="_blank">Aung Khant</a></div>
|
||||
<div align="center" class="style2">
|
||||
<a href="http://www.softwaresecured.com" target="blank">Sherif Koussa</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div align="center" class="style2"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div align="center" class="style2"> </div>
|
||||
<div align="center" class="style2"> </div>
|
||||
<div align="center" class="style2"> </div>
|
||||
<div id="warning">WARNING<br />
|
||||
While running this program, your machine is extremely vulnerable to
|
||||
attack if you are not running on localhost. If you are NOT running on localhost (default configuration), You should disconnect from the network while using this program.
|
||||
<br />
|
||||
<br />
|
||||
This program is for educational purposes only. Use of these techniques
|
||||
without permission could lead to job termination, financial liability,
|
||||
and/or criminal penalties.</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
<%@ page contentType="text/html; charset=ISO-8859-1" language="java"
|
||||
errorPage=""%>
|
||||
<%@page import="org.owasp.webgoat.session.WebSession"%>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||
<%
|
||||
WebSession webSession = ((WebSession) session.getAttribute(WebSession.SESSION));
|
||||
%>
|
||||
@ -60,7 +61,7 @@
|
||||
</head>
|
||||
|
||||
<body class="animated fadeIn" ng-app="goatApp">
|
||||
<section id="container">
|
||||
<section id="container" ng-controller="goatLesson">
|
||||
<header id="header">
|
||||
<!--logo start-->
|
||||
<div class="brand">
|
||||
@ -72,25 +73,37 @@
|
||||
<i class="fa fa-bars"></i>
|
||||
</button>
|
||||
</div><!--toggle navigation end-->
|
||||
<div class="lessonTitle">
|
||||
<h1>Lesson Title in here</h1>
|
||||
<div class="lessonTitle" >
|
||||
<h1 id="lessonTitle">Lesson Title in here</h1>
|
||||
</div><!--lesson title end-->
|
||||
<div class="user-nav pull-right">
|
||||
<button type="button" class="btn btn-default">
|
||||
<div class="user-nav pull-right" style="margin-right: 50px;">
|
||||
<div class="dropdown" style="display:inline">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" id="dropdownMenu1" data-toggle="dropdown">
|
||||
<i class="fa fa-user"></i> <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-left" role="menu" aria-labelledby="dropdownMenu1">
|
||||
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">User: TODO</a></li>
|
||||
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">Role: TODO</a></li>
|
||||
<li role="presentation" class="divider"></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1" href="<c:url value="j_spring_security_logout" />">Logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button type="button" class="btn btn-default right_nav_button" ng-click="showAbout()" data-toggle="tooltip" title="About WebGoat">
|
||||
<i class="fa fa-info"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
<i class="fa fa-envelope"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
<i class="fa fa-user"></i>
|
||||
</button>
|
||||
<a href="mailto:someone@example.com?Subject=Hello%20again" target="_top">
|
||||
<button type="button" class="btn btn-default right_nav_button"data-toggle="tooltip" title="Contact Us">
|
||||
<i class="fa fa-envelope"></i>
|
||||
</button>
|
||||
</a>
|
||||
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!--sidebar left start-->
|
||||
<aside class="sidebar">
|
||||
<div id="leftside-navigation" class="nano" ng-controller="goatLessonMenu">
|
||||
<div id="leftside-navigation" class="nano">
|
||||
<ul class="nano-content">
|
||||
<li class="sub-menu" ng-repeat="item in menuTopics">
|
||||
<a ng-click="expanded = !expanded" href=""><i class="fa {{item.class}}"></i><span>{{item.name}}</span></a>
|
||||
@ -112,42 +125,21 @@
|
||||
<!--main content start-->
|
||||
<section class="main-content-wrapper">
|
||||
|
||||
<section id="main-content" ng-controller="lessonHelpController">
|
||||
<section id="main-content" > <!-- ng-controller="lessonController" -->
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-12" align="left">
|
||||
<div class="panel">
|
||||
<div class="panel-body">
|
||||
<button type="button" id="showSourceBtn" class="btn btn-primary">Java [Source]</button>
|
||||
<button type="button" id="showSolutionBtn" class="btn btn-primary">Solution</button>
|
||||
<button type="button" id="showSourceBtn" class="btn btn-primary btn-xs" ng-click="showLessonSource()">Java [Source]</button>
|
||||
<button type="button" id="showSolutionBtn" class="btn btn-primary btn-xs" ng-click="showLessonSolution()">Solution</button>
|
||||
<button type="button" id="showPlanBtn" class="btn btn-primary btn-xs" ng-click="showLessonPlan()">Lesson Plan</button>
|
||||
<button type="button" id="showHintsBtn" class="btn btn-primary btn-xs" ng-click="viewHints()">Hints</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="panel" id="buttonPanel">
|
||||
<button type="button" id="showParamsCookiesBtn" class="btn btn-primary btn-xs" ng-click="viewCookiesAndParams()">Params/Cookies</button>
|
||||
<button type="button" id="showHintsBtn" class="btn btn-primary btn-xs lessonHelpBtn">Hints</button>
|
||||
<button type="button" id="showPlanBtn" class="btn btn-primary btn-xs lessonHelpBtn">Lesson Plan</button>
|
||||
<button type="button" id="showSourceBtn" class="btn btn-primary btn-xs lessonHelpBtn">Java [Source]</button> <!-- ng-click="showSource('lg') -->
|
||||
<button type="button" id="showSolutionBtn" class="btn btn-primary btn-xs lessonHelpBtn">Solution</button> <!-- ng-click="showSolution('lg') -->
|
||||
</div>
|
||||
|
||||
<div class="panel" id="cookiesAndParams">
|
||||
<div class="cookiesView">
|
||||
cookies:
|
||||
<ul ng-repeat="cookie in cookies">
|
||||
<li ng-repeat="(key, value) in cookie">{{key}} :: {{ value}} </td>
|
||||
</ul>
|
||||
</div>
|
||||
<div> <!--class="paramsView"-->
|
||||
params:<br/>
|
||||
<ul>
|
||||
<li ng-repeat="param in params">
|
||||
{{param.name}} = {{param.value}}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<div class="panel" >
|
||||
<div class="panel-body" id="lesson_content">
|
||||
<b>This should default to the "How to Work with Webgoat" lesson</b>
|
||||
@ -161,19 +153,61 @@
|
||||
<div class="panel">
|
||||
<div class="panel-body">
|
||||
<div align="left">
|
||||
<button id="showParamsCookiesBtn" type="button" class="btn btn-default">Params / Cookies</button>
|
||||
<button id="showHintsBtn" type="button" class="btn btn-default">Hints</button>
|
||||
<button id="showPlanBtn" type="button" class="btn btn-default">Lesson Plan</button>
|
||||
<h3>Cookies / Parameters</h3>
|
||||
</div>
|
||||
<hr />
|
||||
<h3>Hints</h3>
|
||||
<p>Nam placerat magna in massa euismod fringilla. Pellentesque in cursus risus, eu hendrerit ligula. Quisque ultrices eget tortor ut eleifend. Praesent auctor libero nec quam fringilla faucibus. Curabitur cursus risus eu faucibus rutrum. Morbi dapibus nulla risus, et euismod eros posuere volutpat. Quisque ut diam diam. Quisque sed enim tortor. Suspendisse commodo magna nec felis ultricies laoreet. Donec sit amet vehicula eros. Phasellus at dapibus enim. Sed massa quam, aliquet eu mattis at, porttitor a nisi.</p>
|
||||
<div id="cookiesAndParamsView">
|
||||
<div class="cookiesView">
|
||||
<h4>Cookies</h4>
|
||||
<table class="cookieTable table-striped table-nonfluid" ng-repeat="cookie in cookies">
|
||||
<thead>
|
||||
<tr><th>Field</th><th>Value</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="(key, value) in cookie">
|
||||
<td>{{key}}</td>
|
||||
<td>{{value}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<!--<li ng-repeat="(key, value) in cookie">{{key}} :: {{ value}} </td>-->
|
||||
<!--</ul>-->
|
||||
</table>
|
||||
</div>
|
||||
<div id="paramsView"> <!--class="paramsView"-->
|
||||
<h4>Params</h4>
|
||||
<table class="paramsTable table-striped table-nonfluid" id="paramsTable">
|
||||
<thead>
|
||||
<tr><th>Param</th><th>Value</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="param in parameters">
|
||||
<td>{{param.name}}</td>
|
||||
<td>{{param.value}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!--col-md-4 end-->
|
||||
</div>
|
||||
<div id="lessonHelpsWrapper">
|
||||
<div class="row lessonHelp" id="lesson_hint_row">
|
||||
<div class="col-md-12">
|
||||
<h4>Hints</h4>
|
||||
<div class="panel" >
|
||||
<div class="panel-body" id="lesson_hint">
|
||||
<span class="glyphicon-class glyphicon glyphicon-circle-arrow-left" id="showPrevHintBtn" ng-click="viewPrevHint()"></span>
|
||||
<span class="glyphicon-class glyphicon glyphicon-circle-arrow-right" id="showNextHintBtn" ng-click="viewNextHint()"></span>
|
||||
<br/>
|
||||
{{curHint}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row lessonHelp" id="lesson_cookies_row">
|
||||
<div class="col-md-12">
|
||||
<h4>Lesson Parameters and Cookies</h4>
|
||||
@ -198,8 +232,8 @@
|
||||
<div class="col-md-12">
|
||||
<h4>Lesson Plan</h4>
|
||||
<div class="panel" >
|
||||
<div class="panel-body" id="lesson_plan">
|
||||
|
||||
<div class="panel-body" id="lesson_plan">
|
||||
<!-- allowing jQuery to handle this one -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -207,8 +241,8 @@
|
||||
<div class="row lessonHelp" id="lesson_solution_row">
|
||||
<div class="col-md-12">
|
||||
<h4>Lesson Solution</h4>
|
||||
<div class="panel" >
|
||||
<div class="panel-body" id="lesson_solution">
|
||||
<div class="panel">
|
||||
<div class="panel-body" id="lesson_solution">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -216,8 +250,9 @@
|
||||
<div class="row lessonHelp" id="lesson_source_row">
|
||||
<div class="col-md-12">
|
||||
<h4>Lesson Source Code</h4>
|
||||
<div class="panel" >
|
||||
<div class="panel-body" id="lesson_source">
|
||||
<div class="panel">
|
||||
<div class="panel-body" id="lesson_source">
|
||||
<pre>{{source}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -237,83 +272,83 @@
|
||||
<!-- TODO pull source into project instead of loading from external -->
|
||||
<script src="http://malsup.github.com/jquery.form.js"></script>
|
||||
<script>
|
||||
//Load global functions
|
||||
//Load global functions
|
||||
|
||||
// set this to true if you want to see form submissions
|
||||
// set to false once we get all the kinks worked out
|
||||
var DEBUG_FORM_SUBMISSION = false;
|
||||
// set this to true if you want to see form submissions
|
||||
// set to false once we get all the kinks worked out
|
||||
var DEBUG_FORM_SUBMISSION = false;
|
||||
|
||||
$(document).ready(function() {
|
||||
// bind to click events on menu links
|
||||
/*$('.menu-link').bind('click', function(event) {
|
||||
event.preventDefault();
|
||||
$.get(this.href, {}, function(reply) {
|
||||
$("#lesson_content").html(reply);
|
||||
goat.utils.showLessonSource();
|
||||
}, "html");
|
||||
});*/
|
||||
$(document).ready(function() {
|
||||
app.init();
|
||||
//can be augmented later to 'resume' for a given user ... currently kluged to start at fixed lesson
|
||||
var url = 'attack?Screen=32&menu=5';
|
||||
angular.element($('#leftside-navigation')).scope().renderLesson(url);
|
||||
});
|
||||
// make all forms ajax forms
|
||||
var options = {
|
||||
target: '#lesson_content', // target element(s) to be updated with server response
|
||||
beforeSubmit: showRequest, // pre-submit callback, comment out after debugging
|
||||
success: showResponse // post-submit callback, comment out after debugging
|
||||
|
||||
app.init();
|
||||
// other available options:
|
||||
//url: url // override for form's 'action' attribute
|
||||
//type: type // 'get' or 'post', override for form's 'method' attribute
|
||||
//dataType: null // 'xml', 'script', or 'json' (expected server response type)
|
||||
//clearForm: true // clear all form fields after successful submit
|
||||
//resetForm: true // reset the form after successful submit
|
||||
|
||||
});
|
||||
// make all forms ajax forms
|
||||
var options = {
|
||||
target: '#lesson_content', // target element(s) to be updated with server response
|
||||
beforeSubmit: showRequest, // pre-submit callback, comment out after debugging
|
||||
success: showResponse // post-submit callback, comment out after debugging
|
||||
// $.ajax options can be used here too, for example:
|
||||
//timeout: 3000
|
||||
};
|
||||
// pre-submit callback
|
||||
function showRequest(formData, jqForm, options) {
|
||||
if (DEBUG_FORM_SUBMISSION) {
|
||||
// formData is an array; here we use $.param to convert it to a string to display it
|
||||
// but the form plugin does this for you automatically when it submits the data
|
||||
var queryString = $.param(formData);
|
||||
|
||||
// other available options:
|
||||
//url: url // override for form's 'action' attribute
|
||||
//type: type // 'get' or 'post', override for form's 'method' attribute
|
||||
//dataType: null // 'xml', 'script', or 'json' (expected server response type)
|
||||
//clearForm: true // clear all form fields after successful submit
|
||||
//resetForm: true // reset the form after successful submit
|
||||
// jqForm is a jQuery object encapsulating the form element. To access the
|
||||
// DOM element for the form do this:
|
||||
// var formElement = jqForm[0];
|
||||
|
||||
// $.ajax options can be used here too, for example:
|
||||
//timeout: 3000
|
||||
};
|
||||
// pre-submit callback
|
||||
function showRequest(formData, jqForm, options) {
|
||||
if (DEBUG_FORM_SUBMISSION) {
|
||||
// formData is an array; here we use $.param to convert it to a string to display it
|
||||
// but the form plugin does this for you automatically when it submits the data
|
||||
var queryString = $.param(formData);
|
||||
alert('About to submit: \n\n' + queryString);
|
||||
}
|
||||
|
||||
// jqForm is a jQuery object encapsulating the form element. To access the
|
||||
// DOM element for the form do this:
|
||||
// var formElement = jqForm[0];
|
||||
// here we could return false to prevent the form from being submitted;
|
||||
// returning anything other than false will allow the form submit to continue
|
||||
return true;
|
||||
}
|
||||
|
||||
alert('About to submit: \n\n' + queryString);
|
||||
}
|
||||
// post-submit callback
|
||||
function showResponse(responseText, statusText, xhr, $form) {
|
||||
// for normal html responses, the first argument to the success callback
|
||||
// is the XMLHttpRequest object's responseText property
|
||||
|
||||
// here we could return false to prevent the form from being submitted;
|
||||
// returning anything other than false will allow the form submit to continue
|
||||
return true;
|
||||
}
|
||||
// if the ajaxForm method was passed an Options Object with the dataType
|
||||
// property set to 'xml' then the first argument to the success callback
|
||||
// is the XMLHttpRequest object's responseXML property
|
||||
|
||||
// post-submit callback
|
||||
function showResponse(responseText, statusText, xhr, $form) {
|
||||
// for normal html responses, the first argument to the success callback
|
||||
// is the XMLHttpRequest object's responseText property
|
||||
|
||||
// if the ajaxForm method was passed an Options Object with the dataType
|
||||
// property set to 'xml' then the first argument to the success callback
|
||||
// is the XMLHttpRequest object's responseXML property
|
||||
|
||||
// if the ajaxForm method was passed an Options Object with the dataType
|
||||
// property set to 'json' then the first argument to the success callback
|
||||
// is the json data object returned by the server
|
||||
if (DEBUG_FORM_SUBMISSION) {
|
||||
alert('status: ' + statusText + '\n\nresponseText: \n' + responseText +
|
||||
'\n\nThe output div should have already been updated with the responseText.');
|
||||
}
|
||||
// JASON - SEE THIS HOOK
|
||||
// update lesson cookies and params
|
||||
// make any embedded forms ajaxy
|
||||
goat.utils.showLessonCookiesAndParams();
|
||||
goat.utils.makeFormsAjax();
|
||||
}
|
||||
// if the ajaxForm method was passed an Options Object with the dataType
|
||||
// property set to 'json' then the first argument to the success callback
|
||||
// is the json data object returned by the server
|
||||
if (DEBUG_FORM_SUBMISSION) {
|
||||
alert('status: ' + statusText + '\n\nresponseText: \n' + responseText +
|
||||
'\n\nThe output div should have already been updated with the responseText.');
|
||||
}
|
||||
// JASON - SEE THIS HOOK
|
||||
// update lesson cookies and params
|
||||
// make any embedded forms ajaxy
|
||||
goat.utils.showLessonCookiesAndParams();
|
||||
goat.utils.makeFormsAjax();
|
||||
}
|
||||
|
||||
</script>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="aboutModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -250,7 +250,7 @@ img {
|
||||
}
|
||||
|
||||
.main-content-wrapper #main-content {
|
||||
background: url('img/webBg.png') no-repeat top left;
|
||||
/*background: url('img/webBg.png') no-repeat top left;*/
|
||||
border-top: solid thin #e7e8ec;
|
||||
display: inline-block;
|
||||
padding: 15px 15px 0 15px;
|
||||
@ -781,11 +781,23 @@ fieldset[disabled] .btn-warning.active {
|
||||
.lessonHelp, .lessonHelpBtn {
|
||||
display: none;
|
||||
}
|
||||
/*
|
||||
.paramsView {
|
||||
float:right;
|
||||
width 50%;
|
||||
margin-right:10px;
|
||||
border-left:2px solid #333;
|
||||
|
||||
.table-nonfluid {
|
||||
width:auto;
|
||||
}
|
||||
*/
|
||||
|
||||
.cookieTable tr td, .paramsTable tr td {
|
||||
padding: 3px;
|
||||
max-width: 200px;
|
||||
font-size: x-small;
|
||||
}
|
||||
|
||||
/* HINTS */
|
||||
#hintsViewTop{
|
||||
display: none;
|
||||
background-color: #eee;
|
||||
}
|
||||
.info {
|
||||
color:#e84c3d;
|
||||
font-weight: bold;
|
||||
}
|
@ -19,8 +19,11 @@ var goatConstants = {
|
||||
solutionService:'service/solution.mvc',
|
||||
lessonPlanService:'service/lessonplan.mvc',
|
||||
menuService: 'service/lessonmenu.mvc',
|
||||
lessonTitleService: 'service/lessontitle.mvc',
|
||||
// literals
|
||||
notFound: 'Could not find'
|
||||
notFound: 'Could not find',
|
||||
noHints: 'There are no hints defined.'
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -3,10 +3,12 @@
|
||||
|
||||
/* ### GOAT CONTROLLERS ### */
|
||||
|
||||
/** Menu Controller
|
||||
/** Lesson Controller (includes menu stuff)
|
||||
* prepares and updates menu topic items for the view
|
||||
*/
|
||||
goat.controller('goatLessonMenu', function($scope, $http, $modal, $log, $templateCache) {
|
||||
goat.controller('goatLesson', function($scope, $http, $modal, $log, $templateCache) {
|
||||
$scope.cookies = [];
|
||||
$scope.params = [];
|
||||
//TODO: implement via separate promise and use config for menu (goat.data.loadMenuData())
|
||||
$http({method: 'GET', url: goatConstants.lessonService}).then(
|
||||
function(menuData) {
|
||||
@ -18,85 +20,156 @@ goat.controller('goatLessonMenu', function($scope, $http, $modal, $log, $templat
|
||||
console.error("Error rendering menu: " + error);
|
||||
}
|
||||
);
|
||||
|
||||
$scope.renderLesson = function(url) {
|
||||
//console.log(url + ' was passed in');
|
||||
// use jquery to render lesson content to div
|
||||
$scope.hintIndex = 0;
|
||||
|
||||
var curScope = $scope;
|
||||
|
||||
curScope.parameters = goat.utils.scrapeParams(url);
|
||||
goat.data.loadLessonContent(url).then(
|
||||
function(reply) {
|
||||
$("#lesson_content").html(reply);
|
||||
// hook forms
|
||||
goat.data.loadLessonTitle().then(
|
||||
function(reply) {
|
||||
$("#lessonTitle").text(reply);
|
||||
}
|
||||
);
|
||||
|
||||
//hook forms
|
||||
goat.utils.makeFormsAjax();
|
||||
//render lesson title
|
||||
$('#lessonTitle').text(goat.utils.extractLessonTitle($(reply)));
|
||||
$('#hintsView').hide();
|
||||
// adjust menu to lessonContent size if necssary
|
||||
//@TODO: this is still clunky ... needs some TLC
|
||||
//@TODO: this is still clunky ... needs some TLC
|
||||
if ($('div.panel-body').height() > 400) {
|
||||
$('#leftside-navigation').height($(window).height());
|
||||
}
|
||||
goat.lesson.lessonInfo = new goat.lesson.CurLesson(url);
|
||||
goat.lesson.lessonInfo.loadInfo(); //uses pseudo and actual service calls
|
||||
// @TODO: convert to real services (and more angularjs, likely ... in phase 2)
|
||||
//cookies
|
||||
goat.data.loadCookies().then(
|
||||
function(resp) {
|
||||
curScope.cookies = resp;
|
||||
}
|
||||
);
|
||||
//hints
|
||||
curScope.hintIndex = 0;
|
||||
goat.data.loadHints().then(
|
||||
function(resp) {
|
||||
curScope.hints = resp;
|
||||
if (curScope.hints.length > 0 && curScope.hints[0].hint.indexOf(goatConstants.noHints) === -1) {
|
||||
goat.utils.displayButton('showHintsBtn', true);
|
||||
} else {
|
||||
goat.utils.displayButton('showHintsBtn', false);
|
||||
}
|
||||
}
|
||||
);
|
||||
//source
|
||||
goat.data.loadSource().then(
|
||||
function(resp) {
|
||||
curScope.source = resp;
|
||||
}
|
||||
);
|
||||
//plan
|
||||
goat.data.loadPlan().then(
|
||||
function(resp) {
|
||||
curScope.plan = resp;
|
||||
}
|
||||
);
|
||||
//solution
|
||||
goat.data.loadSolution().then(
|
||||
function(resp) {
|
||||
curScope.solution = resp;
|
||||
}
|
||||
);
|
||||
goat.utils.scrollToTop();
|
||||
}
|
||||
);
|
||||
};
|
||||
}).animation('.slideDown', function() {
|
||||
var NgHideClassName = 'ng-hide';
|
||||
return {
|
||||
beforeAddClass: function(element, className, done) {
|
||||
if (className === NgHideClassName) {
|
||||
$(element).slideUp(done);
|
||||
}
|
||||
},
|
||||
removeClass: function(element, className, done) {
|
||||
if (className === NgHideClassName) {
|
||||
$(element).hide().slideDown(done);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
goat.controller('lessonHelpController', function($scope) {
|
||||
$scope.cookies=[];
|
||||
$scope.params=[];
|
||||
$scope.viewCookiesAndParams = function() {
|
||||
$scope.cookies=goat.lesson.lessonInfo.cookies;
|
||||
console.log($scope.cookies);
|
||||
$scope.params=goat.lesson.lessonInfo.params;
|
||||
|
||||
//@TODO: issue callback to track view
|
||||
);
|
||||
};
|
||||
//$scope.watch()
|
||||
|
||||
$scope.showLessonSource = function() {
|
||||
$('.lessonHelp').hide();
|
||||
$('#lesson_source_row').show();
|
||||
goat.utils.scrollToHelp();
|
||||
}
|
||||
|
||||
$scope.showLessonPlan = function() {
|
||||
$('.lessonHelp').hide();
|
||||
$("#lesson_plan").html($scope.plan);
|
||||
$('#lesson_plan_row').show();
|
||||
goat.utils.scrollToHelp();
|
||||
}
|
||||
|
||||
$scope.showLessonSolution = function() {
|
||||
$('.lessonHelp').hide();
|
||||
$("#lesson_solution").html($scope.solution);
|
||||
$('#lesson_solution_row').show();
|
||||
goat.utils.scrollToHelp();
|
||||
}
|
||||
|
||||
$scope.manageHintButtons = function() {
|
||||
if ($scope.hintIndex === $scope.hints.length - 1) {
|
||||
$('#showNextHintBtn').css('visibility', 'hidden');
|
||||
} else if ($scope.hintIndex < $scope.hints.length - 1) {
|
||||
$('#showNextHintBtn').css('visibility', 'visible');
|
||||
}
|
||||
//
|
||||
if ($scope.hintIndex === 0) {
|
||||
$('#showPrevHintBtn').css('visibility', 'hidden');
|
||||
} else if ($scope.hintIndex > 0) {
|
||||
$('#showPrevHintBtn').css('visibility', 'visible');
|
||||
}
|
||||
};
|
||||
|
||||
$scope.viewHints = function() {
|
||||
if (!$scope.hints) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.lessonHelp').hide();
|
||||
$('#lesson_hint_row').show();
|
||||
goat.utils.scrollToHelp();
|
||||
$scope.curHint = $scope.hints[$scope.hintIndex].hint;
|
||||
$scope.manageHintButtons();
|
||||
};
|
||||
|
||||
$scope.viewNextHint = function() {
|
||||
$scope.hintIndex++;
|
||||
$scope.curHint = $scope.hints[$scope.hintIndex].hint;
|
||||
$scope.manageHintButtons();
|
||||
};
|
||||
|
||||
$scope.viewPrevHint = function() {
|
||||
$scope.hintIndex--;
|
||||
$scope.curHint = $scope.hints[$scope.hintIndex].hint;
|
||||
$scope.manageHintButtons();
|
||||
};
|
||||
|
||||
$scope.hideHints = function() {
|
||||
|
||||
};
|
||||
|
||||
$scope.showAbout = function() {
|
||||
$('#aboutModal').modal({
|
||||
remote: 'about.mvc'
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
}).animation('.slideDown', function() {
|
||||
var NgHideClassName = 'ng-hide';
|
||||
return {
|
||||
beforeAddClass: function(element, className, done) {
|
||||
if (className === NgHideClassName) {
|
||||
$(element).slideUp(done);
|
||||
}
|
||||
},
|
||||
removeClass: function(element, className, done) {
|
||||
if (className === NgHideClassName) {
|
||||
$(element).hide().slideDown(done);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
});
|
||||
|
||||
/*
|
||||
*DEPRECATED
|
||||
//Controllers for modal instances
|
||||
var showSourceController = function($scope, $modalInstance, lessonSource) {
|
||||
|
||||
$scope.lessonSource = lessonSource;
|
||||
|
||||
$scope.ok = function() {
|
||||
$modalInstance.close();
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
};
|
||||
|
||||
var showSolutionController = function($scope, $modalInstance, lessonSolutionUrl) {
|
||||
|
||||
$scope.lessonSolutionUrl = lessonSolutionUrl;
|
||||
|
||||
$scope.ok = function() {
|
||||
$modalInstance.close();
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ goat.data = {
|
||||
return $.get(goatConstants.sourceService, {});
|
||||
},
|
||||
loadSolution: function () {
|
||||
return $.get(goatConstants.solutionService, {})
|
||||
return $.get(goatConstants.solutionService, {});
|
||||
},
|
||||
loadPlan: function () {
|
||||
return $.get(goatConstants.lessonPlanService, {});
|
||||
@ -30,5 +30,8 @@ goat.data = {
|
||||
loadMenuData: function() {
|
||||
//TODO use goatConstants var for url
|
||||
return $http({method: 'GET', url: goatConstants.menuService});
|
||||
},
|
||||
loadLessonTitle: function () {
|
||||
return $.get(goatConstants.lessonTitleService, {});
|
||||
}
|
||||
};
|
||||
|
@ -31,7 +31,7 @@ goat.lesson = {
|
||||
goat.data.loadHints().then(
|
||||
function(resp) {
|
||||
scope.hints = resp;
|
||||
if (scope.hints.length > 0) {
|
||||
if (scope.hints.length > 0 && scope.hints[0].hint.indexOf(goatConstants.noHints) === -1) {
|
||||
goat.utils.displayButton('showHintsBtn',true);
|
||||
} else {
|
||||
goat.utils.displayButton('showHintsBtn',false);
|
||||
@ -103,7 +103,7 @@ goat.lesson = {
|
||||
);
|
||||
},
|
||||
getParams: function() {
|
||||
this.params = goat.utils.scrapeParams(this.lessonUrl)
|
||||
this.params = goat.utils.scrapeParams(this.lessonUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,14 +15,6 @@ goat.utils = {
|
||||
//console.log("Hooking any lesson forms to make them ajax");
|
||||
$("form").ajaxForm(options);
|
||||
},
|
||||
/**goatApp.extractLessonTitle
|
||||
*pulls lesson title from html fragment returned (looks for it in h1 element)
|
||||
*@param - html rendered to object passed in
|
||||
*/
|
||||
extractLessonTitle: function(el) {
|
||||
var title = $('h1', el).text();
|
||||
return title;
|
||||
},
|
||||
displayButton: function(id,show) {
|
||||
if ($('#'+id)) {
|
||||
if (show) {
|
||||
@ -44,7 +36,7 @@ goat.utils = {
|
||||
},
|
||||
showLessonSource: function(source) {
|
||||
$('.lessonHelp').hide();
|
||||
$('#lesson_source').html("<pre>"+goat.lesson.lessonInfo.source+"</pre>");
|
||||
//$('#lesson_source').html("<pre>"+goat.lesson.lessonInfo.source+"</pre>");
|
||||
$('#lesson_source_row').show();
|
||||
goat.utils.scrollToHelp();
|
||||
},
|
||||
@ -65,6 +57,7 @@ goat.utils = {
|
||||
goat.utils.scrollEasy(target);
|
||||
},
|
||||
scrollToTop: function() {
|
||||
$('.lessonHelp').hide();
|
||||
var target= $('#container');
|
||||
goat.utils.scrollEasy(target);
|
||||
},
|
||||
|
@ -8,7 +8,7 @@
|
||||
<p>
|
||||
<b>How HTTP works:</b>
|
||||
</p>
|
||||
All HTTP transactions follow the same general format. Each client request and server response has three parts: the request or response line, a header section, and the entity body. The client initiates a transaction as follows: <br>
|
||||
All HTTP transactions follow the same general format. Each client request and server response has three parts: the request or response line, a header section and the entity body. The client initiates a transaction as follows: <br>
|
||||
<br>
|
||||
The client contacts the server and sends a document request <br>
|
||||
</div>
|
||||
@ -20,8 +20,8 @@ All HTTP transactions follow the same general format. Each client request and se
|
||||
After sending the request and headers, the client may send additional data. This data is mostly used by CGI programs using the POST method.<br>
|
||||
<p><b>General Goal(s):</b> </p>
|
||||
<!-- Start Instructions -->
|
||||
Enter your name in the input field below and press "go" to submit. The server will accept the request, reverse the input, and display it back to the user, illustrating the basics of handling an HTTP request.
|
||||
Enter your name in the input field below and press "Go!" to submit. The server will accept the request, reverse the input and display it back to the user, illustrating the basics of handling an HTTP request.
|
||||
<br/><br/>
|
||||
The user should become familiar with the features of WebGoat by manipulating the above
|
||||
buttons to view hints, show the HTTP request parameters, the HTTP request cookies, and the Java source code. You may also try using WebScarab for the first time.
|
||||
buttons to view hints, show the HTTP request parameters, the HTTP request cookies, and the Java source code. You may also try using OWASP Zed Attack Proxy for the first time.
|
||||
<!-- Stop Instructions -->
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 178 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 186 KiB After Width: | Height: | Size: 186 KiB |
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 189 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 170 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 238 B After Width: | Height: | Size: 238 B |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 183 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 172 KiB After Width: | Height: | Size: 172 KiB |
Before Width: | Height: | Size: 174 KiB After Width: | Height: | Size: 174 KiB |
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |