- Added new challenges
- Added new webapplication called WebWolf to make attacks more realistic - Added WebWolf lesson to explain the concepts behind this new application
This commit is contained in:
46
webwolf/README.md
Normal file
46
webwolf/README.md
Normal file
@ -0,0 +1,46 @@
|
||||
# WebWolf
|
||||
|
||||
## Introduction
|
||||
|
||||
During workshops one of the feedback items was that in some lesson it was not clear what you controlled
|
||||
as an attacker and what was part of the lesson. To make this separation more distinct we created
|
||||
WebWolf which is completely controlled by you as the attacker and runs as a separate application.
|
||||
|
||||
Instead of using your own machine which would involve WebGoat being connected to your local network
|
||||
or internet (remember WebGoat is a vulnerable webapplication) we created WebWolf which is the the
|
||||
environment for you as an attacker.
|
||||
|
||||
At the moment WebWolf offers support for:
|
||||
|
||||
- Receiving e-mails
|
||||
- Serving files
|
||||
- Logging of incoming requests (cookies etc)
|
||||
|
||||
## Running
|
||||
|
||||
### Docker
|
||||
|
||||
If you use the Docker image of WebGoat this application will automatically be available. Use the following
|
||||
URL: http://localhost:8081/WebWolf
|
||||
|
||||
### Standalone
|
||||
|
||||
```Shell
|
||||
cd WebGoat
|
||||
git checkout develop
|
||||
mvn clean install
|
||||
```
|
||||
|
||||
Now we are ready to run the project. WebGoat 8.x is using Spring-Boot.
|
||||
|
||||
```Shell
|
||||
mvn -pl webwolf spring-boot:run
|
||||
```
|
||||
... you should be running WebWolf on localhost:8081/WebWolf momentarily
|
||||
|
||||
|
||||
|
||||
### Mapping
|
||||
|
||||
The web application runs on '/' and the controllers and Thymeleaf templates are hardcoded to '/WebWolf' we need
|
||||
to have '/' available which acts as a landing page for incoming requests.
|
111
webwolf/pom.xml
Normal file
111
webwolf/pom.xml
Normal file
@ -0,0 +1,111 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>webwolf</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat</groupId>
|
||||
<artifactId>webgoat-parent</artifactId>
|
||||
<version>8.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.owasp.webgoat</groupId>
|
||||
<artifactId>webgoat-commons</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${guava.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>LATEST</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf.extras</groupId>
|
||||
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-jms</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-activemq</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>bootstrap</artifactId>
|
||||
<version>3.3.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>jquery</artifactId>
|
||||
<version>3.2.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<encoding>ISO-8859-1</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
89
webwolf/src/main/java/org/owasp/webwolf/FileServer.java
Normal file
89
webwolf/src/main/java/org/owasp/webwolf/FileServer.java
Normal file
@ -0,0 +1,89 @@
|
||||
package org.owasp.webwolf;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.Files;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.owasp.webwolf.user.WebGoatUser;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Controller for uploading a file
|
||||
*/
|
||||
@Controller
|
||||
@Slf4j
|
||||
public class FileServer {
|
||||
|
||||
@Value("${webwolf.fileserver.location}")
|
||||
private String fileLocatation;
|
||||
|
||||
@PostMapping(value = "/WebWolf/fileupload")
|
||||
@SneakyThrows
|
||||
public ModelAndView importFile(@RequestParam("file") MultipartFile myFile) {
|
||||
WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
File destinationDir = new File(fileLocatation, user.getUsername());
|
||||
destinationDir.mkdirs();
|
||||
myFile.transferTo(new File(destinationDir, myFile.getOriginalFilename()));
|
||||
log.debug("File saved to {}", new File(destinationDir, myFile.getOriginalFilename()));
|
||||
Files.touch(new File(destinationDir, user.getUsername() + "_changed"));
|
||||
|
||||
ModelMap model = new ModelMap();
|
||||
model.addAttribute("uploadSuccess", "File uploaded successful");
|
||||
return new ModelAndView(
|
||||
new RedirectView("files", true),
|
||||
model
|
||||
);
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
private class UploadedFile {
|
||||
private final String name;
|
||||
private final String size;
|
||||
private final String link;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/WebWolf/files")
|
||||
public ModelAndView getFiles(HttpServletRequest request) {
|
||||
WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
String username = user.getUsername();
|
||||
File destinationDir = new File(fileLocatation, username);
|
||||
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
modelAndView.setViewName("files");
|
||||
File changeIndicatorFile = new File(destinationDir, user.getUsername() + "_changed");
|
||||
if (changeIndicatorFile.exists()) {
|
||||
modelAndView.addObject("uploadSuccess", request.getParameter("uploadSuccess"));
|
||||
}
|
||||
changeIndicatorFile.delete();
|
||||
|
||||
List<UploadedFile> uploadedFiles = Lists.newArrayList();
|
||||
File[] files = destinationDir.listFiles(File::isFile);
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
String size = FileUtils.byteCountToDisplaySize(file.length());
|
||||
String link = String.format("files/%s/%s", username, file.getName());
|
||||
uploadedFiles.add(new UploadedFile(file.getName(), size, link));
|
||||
}
|
||||
}
|
||||
|
||||
modelAndView.addObject("files", uploadedFiles);
|
||||
return modelAndView;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package org.owasp.webwolf;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/13/17.
|
||||
*/
|
||||
@Configuration
|
||||
public class MvcConfiguration extends WebMvcConfigurerAdapter {
|
||||
|
||||
@Value("${webwolf.fileserver.location}")
|
||||
private String fileLocatation;
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/files/**").addResourceLocations("file:///" + fileLocatation + "/");
|
||||
super.addResourceHandlers(registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/login").setViewName("login");
|
||||
registry.addViewController("/WebWolf/home").setViewName("home");
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void createDirectory() {
|
||||
File file = new File(fileLocatation);
|
||||
if (!file.exists()) {
|
||||
file.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
|
||||
/**
|
||||
* ************************************************************************************************
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details,
|
||||
* please see http://www.owasp.org/
|
||||
* <p>
|
||||
* Copyright (c) 2002 - 20014 Bruce Mayhew
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Getting Source ==============
|
||||
* <p>
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software
|
||||
* projects.
|
||||
* <p>
|
||||
*
|
||||
* @author WebGoat
|
||||
* @version $Id: $Id
|
||||
* @since December 12, 2015
|
||||
*/
|
||||
package org.owasp.webwolf;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webwolf.user.UserService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
/**
|
||||
* Security configuration for WebGoat.
|
||||
*/
|
||||
@Configuration
|
||||
@AllArgsConstructor
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
private final UserService userDetailsService;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry security = http
|
||||
.authorizeRequests()
|
||||
.antMatchers("/css/**", "/images/**", "/js/**", "/fonts/**", "/webjars/**").permitAll()
|
||||
.antMatchers("/WebWolf/**").authenticated()
|
||||
.anyRequest().permitAll();
|
||||
security.and().csrf().disable().formLogin()
|
||||
.loginPage("/login").failureUrl("/login?error=true");
|
||||
security.and()
|
||||
.formLogin()
|
||||
.loginPage("/login")
|
||||
.defaultSuccessUrl("/WebWolf/home", true)
|
||||
.permitAll();
|
||||
security.and()
|
||||
.logout()
|
||||
.permitAll();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth.userDetailsService(userDetailsService); //.passwordEncoder(bCryptPasswordEncoder());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public UserDetailsService userDetailsServiceBean() throws Exception {
|
||||
return userDetailsService;
|
||||
}
|
||||
}
|
59
webwolf/src/main/java/org/owasp/webwolf/WebWolf.java
Normal file
59
webwolf/src/main/java/org/owasp/webwolf/WebWolf.java
Normal file
@ -0,0 +1,59 @@
|
||||
package org.owasp.webwolf;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webwolf.requests.WebWolfTraceRepository;
|
||||
import org.owasp.webwolf.user.WebGoatUserToCookieRepository;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
|
||||
import org.springframework.jms.config.JmsListenerContainerFactory;
|
||||
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
|
||||
import org.springframework.jms.support.converter.MessageConverter;
|
||||
import org.springframework.jms.support.converter.MessageType;
|
||||
|
||||
import javax.jms.ConnectionFactory;
|
||||
|
||||
|
||||
@SpringBootApplication
|
||||
@Slf4j
|
||||
public class WebWolf extends SpringBootServletInitializer {
|
||||
|
||||
@Bean
|
||||
public TraceRepository traceRepository(WebGoatUserToCookieRepository repository) {
|
||||
return new WebWolfTraceRepository(repository);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
|
||||
return application.sources(WebWolf.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JmsListenerContainerFactory<?> jmsFactory(ConnectionFactory connectionFactory,
|
||||
DefaultJmsListenerContainerFactoryConfigurer configurer) {
|
||||
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
|
||||
// This provides all boot's default to this factory, including the message converter
|
||||
configurer.configure(factory, connectionFactory);
|
||||
// You could still override some of Boot's default if necessary.
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageConverter jacksonJmsMessageConverter(ObjectMapper objectMapper) {
|
||||
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
|
||||
converter.setTargetType(MessageType.TEXT);
|
||||
converter.setTypeIdPropertyName("_type");
|
||||
converter.setObjectMapper(objectMapper);
|
||||
return converter;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication.run(WebWolf.class, args);
|
||||
}
|
||||
}
|
42
webwolf/src/main/java/org/owasp/webwolf/mailbox/Email.java
Normal file
42
webwolf/src/main/java/org/owasp/webwolf/mailbox/Email.java
Normal file
@ -0,0 +1,42 @@
|
||||
package org.owasp.webwolf.mailbox;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
@Builder
|
||||
@Data
|
||||
@Document
|
||||
public class Email implements Serializable {
|
||||
|
||||
@Id
|
||||
private String id;
|
||||
private LocalDateTime time;
|
||||
private String contents;
|
||||
private String sender;
|
||||
private String title;
|
||||
@Indexed
|
||||
private String recipient;
|
||||
|
||||
public String getSummary() {
|
||||
return "-" + this.contents.substring(0, 50);
|
||||
}
|
||||
|
||||
public String getTime() {
|
||||
return DateTimeFormatter.ofPattern("h:mm a").format(time);
|
||||
}
|
||||
|
||||
public String getShortSender() {
|
||||
return sender.substring(0, sender.indexOf("@"));
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package org.owasp.webwolf.mailbox;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.owasp.webwolf.user.WebGoatUser;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/17/17.
|
||||
*/
|
||||
@RestController
|
||||
@AllArgsConstructor
|
||||
public class MailboxController {
|
||||
|
||||
private final MailboxRepository mailboxRepository;
|
||||
|
||||
@GetMapping(value = "/WebWolf/mail")
|
||||
public ModelAndView mail() {
|
||||
WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
ModelAndView modelAndView = new ModelAndView();
|
||||
List<Email> emails = mailboxRepository.findByRecipientOrderByTimeDesc(user.getUsername());
|
||||
if (emails != null && !emails.isEmpty()) {
|
||||
modelAndView.addObject("total", emails.size());
|
||||
modelAndView.addObject("emails", emails);
|
||||
}
|
||||
modelAndView.setViewName("mailbox");
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package org.owasp.webwolf.mailbox;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.mail.IncomingMailEvent;
|
||||
import org.owasp.webwolf.user.UserRepository;
|
||||
import org.springframework.jms.annotation.JmsListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
public class MailboxListener {
|
||||
|
||||
private final MailboxRepository repository;
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@JmsListener(destination = "mailbox", containerFactory = "jmsFactory")
|
||||
public void incomingMail(IncomingMailEvent event) {
|
||||
if (userRepository.findByUsername(event.getRecipient()) != null) {
|
||||
Email email = Email.builder()
|
||||
.contents(event.getContents())
|
||||
.sender(event.getSender())
|
||||
.time(event.getTime())
|
||||
.recipient(event.getRecipient())
|
||||
.title(event.getTitle()).build();
|
||||
repository.save(email);
|
||||
} else {
|
||||
log.trace("Mail received for unknown user: {}", event.getRecipient());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package org.owasp.webwolf.mailbox;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/17/17.
|
||||
*/
|
||||
public interface MailboxRepository extends MongoRepository<Email, ObjectId> {
|
||||
|
||||
List<Email> findByRecipientOrderByTimeDesc(String recipient);
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package org.owasp.webwolf.requests;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webwolf.user.WebGoatUser;
|
||||
import org.springframework.boot.actuate.trace.Trace;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* Controller for fetching all the HTTP requests from WebGoat to WebWolf for a specific
|
||||
* user.
|
||||
*
|
||||
* @author nbaars
|
||||
* @since 8/13/17.
|
||||
*/
|
||||
@Controller
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
@RequestMapping(value = "/WebWolf/requests")
|
||||
public class Requests {
|
||||
|
||||
private final WebWolfTraceRepository traceRepository;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
private class Tracert {
|
||||
private final Date date;
|
||||
private final String path;
|
||||
private final String json;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ModelAndView get(HttpServletRequest request) {
|
||||
ModelAndView m = new ModelAndView("requests");
|
||||
WebGoatUser user = (WebGoatUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
|
||||
List<Tracert> traces = traceRepository.findTraceForUser(user.getUsername()).stream()
|
||||
.map(t -> new Tracert(t.getTimestamp(), path(t), toJsonString(t))).collect(toList());
|
||||
m.addObject("traces", traces);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
private String path(Trace t) {
|
||||
return (String) t.getInfo().getOrDefault("path", "");
|
||||
}
|
||||
|
||||
private String toJsonString(Trace t) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(t.getInfo());
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("Unable to create json", e);
|
||||
}
|
||||
return "No request(s) found";
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package org.owasp.webwolf.requests;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webwolf.user.WebGoatUser;
|
||||
import org.owasp.webwolf.user.WebGoatUserCookie;
|
||||
import org.owasp.webwolf.user.WebGoatUserToCookieRepository;
|
||||
import org.springframework.boot.actuate.trace.Trace;
|
||||
import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
|
||||
import java.net.HttpCookie;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
|
||||
import static java.util.Optional.of;
|
||||
|
||||
/**
|
||||
* Keep track of all the incoming requests, we are only keeping track of request originating from
|
||||
* WebGoat and only if there is a cookie (otherwise we can never relate it back to a user).
|
||||
*
|
||||
* @author nbaars
|
||||
* @since 8/13/17.
|
||||
*/
|
||||
@Slf4j
|
||||
public class WebWolfTraceRepository implements TraceRepository {
|
||||
|
||||
private final LoadingCache<String, ConcurrentLinkedDeque<Trace>> cookieTraces = CacheBuilder.newBuilder()
|
||||
.maximumSize(4000).build(new CacheLoader<String, ConcurrentLinkedDeque<Trace>>() {
|
||||
@Override
|
||||
public ConcurrentLinkedDeque<Trace> load(String s) throws Exception {
|
||||
return new ConcurrentLinkedDeque<>();
|
||||
}
|
||||
});
|
||||
private final WebGoatUserToCookieRepository repository;
|
||||
|
||||
public WebWolfTraceRepository(WebGoatUserToCookieRepository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Trace> findAll() {
|
||||
HashMap<String, Object> map = Maps.newHashMap();
|
||||
map.put("nice", "Great you found the standard Spring Boot tracing endpoint!");
|
||||
Trace trace = new Trace(new Date(), map);
|
||||
return Lists.newArrayList(trace);
|
||||
}
|
||||
|
||||
public List<Trace> findTraceForUser(String username) {
|
||||
return Lists.newArrayList(cookieTraces.getUnchecked(username));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Map<String, Object> map) {
|
||||
Optional<String> host = getFromHeaders("host", map);
|
||||
String path = (String) map.getOrDefault("path", "");
|
||||
if (host.isPresent() && ("/".equals(path) || path.contains("challenge"))) {
|
||||
Optional<String> cookie = getFromHeaders("cookie", map);
|
||||
cookie.ifPresent(c -> {
|
||||
Optional<String> user = findUserBasedOnCookie(c);
|
||||
user.ifPresent(u -> {
|
||||
ConcurrentLinkedDeque<Trace> traces = this.cookieTraces.getUnchecked(u);
|
||||
traces.addFirst(new Trace(new Date(), map));
|
||||
cookieTraces.put(u, traces);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<String> findUserBasedOnCookie(String cookiesIncomingRequest) {
|
||||
//Request from WebGoat to WebWolf will contain the session cookie of WebGoat try to map it to a user
|
||||
//this mapping is added to userSession by the CookieFilter in WebGoat code
|
||||
HttpCookie cookie = HttpCookie.parse(cookiesIncomingRequest).get(0);
|
||||
Optional<WebGoatUserCookie> userToCookie = repository.findByCookie(cookie.getValue());
|
||||
Optional<String> user = userToCookie.map(u -> u.getUsername());
|
||||
|
||||
if (!user.isPresent()) {
|
||||
//User is maybe logged in to WebWolf use this user
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication != null && authentication.getPrincipal() instanceof WebGoatUser) {
|
||||
WebGoatUser wg = (WebGoatUser) authentication.getPrincipal();
|
||||
user = of(wg.getUsername());
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
private Optional<String> getFromHeaders(String header, Map<String, Object> map) {
|
||||
Map<String, Object> headers = (Map<String, Object>) map.get("headers");
|
||||
if (headers != null) {
|
||||
Map<String, Object> request = (Map<String, Object>) headers.get("request");
|
||||
if (request != null) {
|
||||
return Optional.ofNullable((String) request.get(header));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package org.owasp.webwolf.user;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.owasp.webgoat.login.LoginEvent;
|
||||
import org.owasp.webgoat.login.LogoutEvent;
|
||||
import org.springframework.jms.annotation.JmsListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class LoginListener {
|
||||
|
||||
private final WebGoatUserToCookieRepository repository;
|
||||
|
||||
@JmsListener(destination = "webgoat", containerFactory = "jmsFactory", selector = "type = 'LoginEvent'")
|
||||
public void loginEvent(LoginEvent loginEvent) {
|
||||
log.trace("Login event occurred for user: '{}'", loginEvent.getUser());
|
||||
repository.save(new WebGoatUserCookie(loginEvent.getUser(), loginEvent.getCookie()));
|
||||
}
|
||||
|
||||
@JmsListener(destination = "webgoat", containerFactory = "jmsFactory", selector = "type = 'LogoutEvent'")
|
||||
public void logoutEvent(LogoutEvent logoutEvent) {
|
||||
repository.delete(logoutEvent.getUser());
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package org.owasp.webwolf.user;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
public interface UserRepository extends MongoRepository<WebGoatUser, String> {
|
||||
|
||||
WebGoatUser findByUsername(String username);
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package org.owasp.webwolf.user;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class UserService implements UserDetailsService {
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public WebGoatUser loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
WebGoatUser webGoatUser = userRepository.findByUsername(username);
|
||||
if (webGoatUser == null) {
|
||||
throw new UsernameNotFoundException("User not found");
|
||||
} else {
|
||||
webGoatUser.createUser();
|
||||
}
|
||||
return webGoatUser;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package org.owasp.webwolf.user;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/19/17.
|
||||
*/
|
||||
@Getter
|
||||
public class WebGoatUser implements UserDetails {
|
||||
|
||||
public static final String ROLE_USER = "WEBGOAT_USER";
|
||||
public static final String ROLE_ADMIN = "WEBGOAT_ADMIN";
|
||||
|
||||
@Id
|
||||
private String username;
|
||||
private String password;
|
||||
private String role = ROLE_USER;
|
||||
@Transient
|
||||
private User user;
|
||||
|
||||
protected WebGoatUser() {
|
||||
}
|
||||
|
||||
public WebGoatUser(String username, String password) {
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
createUser();
|
||||
}
|
||||
|
||||
public void createUser() {
|
||||
this.user = new User(username, password, getAuthorities());
|
||||
}
|
||||
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return Collections.singleton(new SimpleGrantedAuthority(getRole()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return this.user.isAccountNonExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return this.user.isAccountNonLocked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return this.user.isCredentialsNonExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.user.isEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
package org.owasp.webwolf.user;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WebGoatUserCookie implements Serializable {
|
||||
|
||||
@Id
|
||||
private String username;
|
||||
private String cookie;
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package org.owasp.webwolf.user;
|
||||
|
||||
import org.springframework.data.mongodb.repository.MongoRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 8/20/17.
|
||||
*/
|
||||
public interface WebGoatUserToCookieRepository extends MongoRepository<WebGoatUserCookie, String> {
|
||||
|
||||
Optional<WebGoatUserCookie> findByCookie(String cookie);
|
||||
}
|
41
webwolf/src/main/resources/application.properties
Normal file
41
webwolf/src/main/resources/application.properties
Normal file
@ -0,0 +1,41 @@
|
||||
server.error.include-stacktrace=always
|
||||
server.error.path=/error.html
|
||||
server.session.timeout=600
|
||||
#server.contextPath=/WebWolf
|
||||
server.port=8081
|
||||
server.session.cookie.name = WEBWOLFSESSION
|
||||
|
||||
logging.level.org.springframework=INFO
|
||||
logging.level.org.springframework.boot.devtools=WARN
|
||||
logging.level.org.owasp=DEBUG
|
||||
logging.level.org.owasp.webwolf=TRACE
|
||||
logging.level.org.apache.activemq=WARN
|
||||
|
||||
|
||||
endpoints.trace.sensitive=false
|
||||
management.trace.include=REQUEST_HEADERS,RESPONSE_HEADERS,COOKIES,ERRORS,TIME_TAKEN,PARAMETERS,QUERY_STRING
|
||||
endpoints.trace.enabled=true
|
||||
|
||||
spring.resources.cache-period=0
|
||||
spring.thymeleaf.cache=false
|
||||
|
||||
multipart.enabled=true
|
||||
multipart.file-size-threshold=0 #
|
||||
multipart.location=${java.io.tmpdir}
|
||||
multipart.max-file-size=1Mb
|
||||
multipart.max-request-size=1Mb
|
||||
|
||||
webwolf.fileserver.location=${java.io.tmpdir}/webwolf-fileserver
|
||||
|
||||
|
||||
spring.data.mongodb.port=27017
|
||||
spring.data.mongodb.database=webgoat
|
||||
|
||||
spring.jackson.serialization.indent_output=true
|
||||
spring.jackson.serialization.write-dates-as-timestamps=false
|
||||
|
||||
spring.activemq.broker-url=tcp://localhost:61616
|
||||
spring.activemq.in-memory=true
|
||||
|
||||
#For static file refresh ... and faster dev :D
|
||||
spring.devtools.restart.additional-paths=webwolf/src/main/resources/static/
|
87
webwolf/src/main/resources/static/css/main.css
Normal file
87
webwolf/src/main/resources/static/css/main.css
Normal file
@ -0,0 +1,87 @@
|
||||
footer {
|
||||
margin-top: 200px;
|
||||
}
|
||||
|
||||
.thead-inverse th {
|
||||
color: #fff;
|
||||
background-color: #373a3c;
|
||||
}
|
||||
|
||||
.left15 {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.top5 {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.top7 {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.top10 {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.top15 {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.top17 {
|
||||
margin-top: 17px;
|
||||
}
|
||||
|
||||
.top30 {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.bottom10 {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#accordion .panel-heading {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#accordion .panel-title > a {
|
||||
display: block;
|
||||
padding: 0.4em 0.6em;
|
||||
outline: none;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#accordion .panel-title > a.accordion-toggle::before, #accordion a[data-toggle="collapse"]::before {
|
||||
content: "\e113";
|
||||
float: left;
|
||||
font-family: 'Glyphicons Halflings';
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
#accordion .panel-title > a.accordion-toggle.collapsed::before, #accordion a.collapsed[data-toggle="collapse"]::before {
|
||||
content: "\e114";
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 250px;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
padding: 1%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*Mailbox*/
|
||||
|
||||
.nav-tabs .glyphicon:not(.no-margin) { margin-right:10px; }
|
||||
.tab-pane .list-group-item:first-child {border-top-right-radius: 0px;border-top-left-radius: 0px;}
|
||||
.tab-pane .list-group-item:last-child {border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;}
|
||||
.tab-pane .list-group .checkbox { display: inline-block;margin: 0px; }
|
||||
.tab-pane .list-group input[type="checkbox"]{ margin-top: 2px; }
|
||||
.tab-pane .list-group .glyphicon { margin-right:5px; }
|
||||
.tab-pane .list-group .glyphicon:hover { color:#FFBC00; }
|
||||
a.list-group-item.read { color: #222;background-color: #F3F3F3; }
|
||||
hr { margin-top: 5px;margin-bottom: 10px; }
|
||||
.nav-pills>li>a {padding: 5px 10px;}
|
||||
|
BIN
webwolf/src/main/resources/static/images/wolf.png
Normal file
BIN
webwolf/src/main/resources/static/images/wolf.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.8 KiB |
80
webwolf/src/main/resources/static/images/wolf.svg
Normal file
80
webwolf/src/main/resources/static/images/wolf.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 9.7 KiB |
15
webwolf/src/main/resources/static/js/fileUpload.js
Normal file
15
webwolf/src/main/resources/static/js/fileUpload.js
Normal file
@ -0,0 +1,15 @@
|
||||
$(document).ready(function() {
|
||||
window.setTimeout(function () {
|
||||
$(".fileUploadAlert").fadeTo(500, 0).slideUp(500, function () {
|
||||
$(this).hide();
|
||||
});
|
||||
}, 4000);
|
||||
});
|
||||
|
||||
$(document).on('click','.fa-files-o',function(){
|
||||
var link = $('#fileLink').attr("href");
|
||||
console.log("testing" + document.protocol + "//" + (document.hostname || document.pathname + link));
|
||||
|
||||
|
||||
document.execCommand('copy');
|
||||
});
|
10
webwolf/src/main/resources/static/js/mail.js
Normal file
10
webwolf/src/main/resources/static/js/mail.js
Normal file
@ -0,0 +1,10 @@
|
||||
$(document).ready(function () {
|
||||
$('.showMail').click(function (e) {
|
||||
e.preventDefault();
|
||||
$(this).parent().find('.contents').toggle()
|
||||
});
|
||||
});
|
||||
|
||||
function refreshEmails() {
|
||||
location.reload();
|
||||
}
|
72
webwolf/src/main/resources/templates/files.html
Normal file
72
webwolf/src/main/resources/templates/files.html
Normal file
@ -0,0 +1,72 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<div th:replace="fragments/header :: header-css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div th:replace="fragments/header :: header"/>
|
||||
|
||||
<script type="text/javascript" th:src="@{/js/fileUpload.js}"></script>
|
||||
|
||||
<div class="container">
|
||||
|
||||
|
||||
<div class="alert alert-info fade in">
|
||||
|
||||
<a href="#" class="close" data-dismiss="alert">×</a>
|
||||
<p>
|
||||
Upload a file which you need to host as an attacker.
|
||||
</p>
|
||||
<p>
|
||||
Each file will be available under the following url:
|
||||
http://localhost:8081/files/{username}/{filename}.
|
||||
</p>
|
||||
<p>
|
||||
You can copy and paste the location from the table below.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Upload a file</strong>
|
||||
<small></small>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<!-- Standar Form -->
|
||||
<form th:action="@{/WebWolf/fileupload}" method="post" enctype="multipart/form-data">
|
||||
<div class="form-inline">
|
||||
<div class="form-group">
|
||||
<input type="file" name="file"/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-md btn-primary">Upload files</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="fileUploadAlert alert-success top10" role="alert">
|
||||
<span th:text="${uploadSuccess}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table">
|
||||
<thead class="thead-inverse">
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Size</th>
|
||||
<th>Link</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="f : ${files}">
|
||||
<td th:text="${f.name}">filename</td>
|
||||
<td th:text="${f.size}">size</td>
|
||||
<td><a th:id="fileLink" th:href="@{'/' + ${f.link}}">link</a>
|
||||
<span class="fa fa-files-o" title="Click to copy to clipboard"></span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
19
webwolf/src/main/resources/templates/fragments/footer.html
Normal file
19
webwolf/src/main/resources/templates/fragments/footer.html
Normal file
@ -0,0 +1,19 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<div th:fragment="footer">
|
||||
|
||||
<div class="container">
|
||||
|
||||
<footer>
|
||||
© 2017 WebGoat - Use WebWolf at your own risk
|
||||
<script type="text/javascript"
|
||||
src="webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
51
webwolf/src/main/resources/templates/fragments/header.html
Normal file
51
webwolf/src/main/resources/templates/fragments/header.html
Normal file
@ -0,0 +1,51 @@
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
|
||||
<head>
|
||||
<title>WebWolf</title>
|
||||
<div th:fragment="header-css">
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="/webjars/bootstrap/3.3.7/css/bootstrap.min.css"/>
|
||||
<!--<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet"/>-->
|
||||
<link rel="stylesheet" th:href="@{/css/main.css}"/>
|
||||
<script src="/webjars/jquery/3.2.1/jquery.min.js"></script>
|
||||
<script src="/webjars/bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||
</div>
|
||||
</head>
|
||||
<body>
|
||||
<div th:fragment="header">
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" th:href="@{/WebWolf/home}">WebWolf</a>
|
||||
</div>
|
||||
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a th:href="@{/WebWolf/home}">Home</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a th:href="@{/WebWolf/files}">Files</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a th:href="@{/WebWolf/mail}">Mailbox</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a th:href="@{/WebWolf/requests}">Incoming requests</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
|
||||
<li><a href="#">
|
||||
<span sec:authorize="isAuthenticated()">
|
||||
<span class="glyphicon glyphicon-user"></span>
|
||||
<span th:text="${#authentication.name}"></span></span></a>
|
||||
</li>
|
||||
<li><a th:href="@{/logout}">
|
||||
<span sec:authorize="isAuthenticated()">
|
||||
Sign out</span></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
37
webwolf/src/main/resources/templates/home.html
Normal file
37
webwolf/src/main/resources/templates/home.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<div th:replace="fragments/header :: header-css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div th:replace="fragments/header :: header"/>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="media">
|
||||
<span class="media-left">
|
||||
<img th:src="@{/images/wolf.png}" class="img-fluid"></img>
|
||||
</span>
|
||||
<div class="media-body">
|
||||
<h1 class="media-heading">WebWolf</h1>
|
||||
<br/>
|
||||
<p>
|
||||
Some challenges requires to have a local web server running. WebWolf is for you the attacker it
|
||||
helps you while solving some of the assignments and challenges within
|
||||
WebGoat. An assignment might for example require you to serve a file or connect back to your own
|
||||
environment or to receive an e-mail.
|
||||
In order to not let you run WebGoat open and connected to the internet we provided these tools in this
|
||||
application, called WebWolf.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- /.container -->
|
||||
|
||||
<div th:replace="fragments/footer :: footer"/>
|
||||
|
||||
</body>
|
||||
</html>
|
58
webwolf/src/main/resources/templates/login.html
Normal file
58
webwolf/src/main/resources/templates/login.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||
>
|
||||
<head>
|
||||
<title>WebWolf</title>
|
||||
<div th:replace="fragments/header :: header-css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div th:replace="fragments/header :: header"/>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<div class="row" style="margin-top:20px">
|
||||
<div class="col-xs-12 col-sm-8 col-md-6 col-sm-offset-2 col-md-offset-3" th:style="'background:url(' + @{/images/wolf.png} + ') no-repeat right;'">
|
||||
<form th:action="@{/login}" method="post">
|
||||
<fieldset>
|
||||
<h2>Sign in</h2>
|
||||
Use your WebGoat account.
|
||||
<br/>
|
||||
<div th:if="${param.error}">
|
||||
<div class="alert alert-danger">
|
||||
Invalid username or password.
|
||||
</div>
|
||||
</div>
|
||||
<div th:if="${param.logout}">
|
||||
<div class="alert alert-info">
|
||||
You have been logged out.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<input type="text" name="username" id="username" class="form-control input-lg"
|
||||
placeholder="UserName" required="true" autofocus="true"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" name="password" id="password" class="form-control input-lg"
|
||||
placeholder="Password" required="true"/>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-sm-6 col-md-6">
|
||||
<input type="submit" class="btn btn-lg btn-primary btn-block" value="Sign In"/>
|
||||
</div>
|
||||
<div class="col-xs-6 col-sm-6 col-md-6">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div th:replace="fragments/footer :: footer"/>
|
||||
|
||||
</body>
|
||||
</html>
|
150
webwolf/src/main/resources/templates/mailbox.html
Normal file
150
webwolf/src/main/resources/templates/mailbox.html
Normal file
@ -0,0 +1,150 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<title>WebWolf</title>
|
||||
<div th:replace="fragments/header :: header-css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div th:replace="fragments/header :: header"/>
|
||||
|
||||
<script type="text/javascript" th:src="@{/js/mail.js}"></script>
|
||||
|
||||
<div class="container">
|
||||
|
||||
|
||||
<div class="alert alert-info fade in">
|
||||
|
||||
<a href="#" class="close" data-dismiss="alert">×</a>
|
||||
<p>
|
||||
The mailbox of you as an attacker, all the mail send to {user}@{random} will be send to this mailbox.
|
||||
</p>
|
||||
<p>
|
||||
Only the user part is important the domain can be anything
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-md-2">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
|
||||
Mail <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="#">Mail</a></li>
|
||||
<li><a href="#">Contacts</a></li>
|
||||
<li><a href="#">Tasks</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-9 col-md-10">
|
||||
<button type="button" class="btn btn-default" data-toggle="tooltip" title="Refresh" onclick="refreshEmails()">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<!-- Single button -->
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
More <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="#">Mark all as read</a></li>
|
||||
<li class="divider"></li>
|
||||
<li class="text-center">
|
||||
<small class="text-muted">Select messages to see more actions</small>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<span class="text-muted"><b>1</b>–<b><span th:text="${total}"> 50</span> </b> of <b><span th:utext="${total}"></span></b></span>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<button type="button" class="btn btn-default">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default">
|
||||
<span class="glyphicon glyphicon-chevron-right"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-sm-3 col-md-2">
|
||||
<a href="#" class="btn btn-danger btn-sm btn-block" role="button">COMPOSE</a>
|
||||
<hr/>
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li class="active"><a href="#"><span class="badge pull-right" th:utext="${total}">42</span>
|
||||
Inbox </a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-sm-9 col-md-10">
|
||||
<!-- Nav tabs -->
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#home" data-toggle="tab"><span class="glyphicon glyphicon-inbox">
|
||||
</span>Primary</a></li>
|
||||
<li><a href="#profile" data-toggle="tab"><span class="glyphicon glyphicon-user"></span>
|
||||
Social</a></li>
|
||||
<li><a href="#messages" data-toggle="tab"><span class="glyphicon glyphicon-tags"></span>
|
||||
Promotions</a></li>
|
||||
<li><a href="#settings" data-toggle="tab"><span class="glyphicon glyphicon-plus no-margin">
|
||||
</span></a></li>
|
||||
</ul>
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade in active" id="home">
|
||||
<span th:each="mail : ${emails}" class="list-group">
|
||||
<a href="#" class="showMail list-group-item">
|
||||
|
||||
|
||||
<span class="glyphicon glyphicon-star-empty"></span>
|
||||
<span class="name"
|
||||
style="min-width: 120px; display: inline-block;"
|
||||
th:text="${mail.shortSender}">WebGoat</span>
|
||||
<span class="" th:text="${mail.title}">Title</span>
|
||||
<span class="text-muted" style="font-size: 11px;" th:text="${mail.summary}">- summary</span>
|
||||
<span class="badge" th:text="${mail.time}">12:10 AM</span>
|
||||
<span class="pull-right">
|
||||
<span class="glyphicon glyphicon-paperclip"></span>
|
||||
</span>
|
||||
</a>
|
||||
<!---->
|
||||
<div class="left15 contents panel panel-default top10" style="display:none" >
|
||||
<div class="panel-heading" >
|
||||
<b><span th:text="${mail.title}"></span></b>
|
||||
<b><span class="pull-right" th:text="${mail.sender}"></span></b>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<pre th:utext="${mail.contents}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</span>
|
||||
|
||||
</div>
|
||||
<div class="tab-pane fade in" id="profile">
|
||||
<div class="list-group">
|
||||
<div class="list-group-item">
|
||||
<span class="text-center">This tab is empty.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade in" id="messages">
|
||||
<div class="list-group-item">
|
||||
<span class="text-center">Why the name "WebGoat"? Developers should not feel bad about not knowing security. Even the best programmers make security errors. What they need is a scapegoat, right? Just blame it on the 'Goat!</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade in" id="settings">
|
||||
This tab is empty.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
56
webwolf/src/main/resources/templates/requests.html
Normal file
56
webwolf/src/main/resources/templates/requests.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<div th:replace="fragments/header :: header-css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div th:replace="fragments/header :: header"/>
|
||||
|
||||
<script type="text/javascript" th:src="@{js/fileUpload.js}"></script>
|
||||
|
||||
<div class="container">
|
||||
|
||||
|
||||
<div class="alert alert-info fade in">
|
||||
|
||||
<a href="#" class="close" data-dismiss="alert">×</a>
|
||||
<p>
|
||||
Challenges in which you need to call your hacker machine WebWolf offers a simple httpd
|
||||
server functionality which only logs the incoming request. You can use the following URL:
|
||||
http://localhost:8081/ and the incoming request will be available below.
|
||||
</p>
|
||||
<p>
|
||||
This is by no means a substitution of httpd but it offers enough functionality to callback to a safe
|
||||
environment and does not require you to host your own httpd server on your local machine.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Requests</h3>
|
||||
<div th:each="trace,iter : ${traces}" class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading" role="tab" th:id="'heading' + ${iter.index}">
|
||||
<h4 class="panel-title">
|
||||
<a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion"
|
||||
th:href="'#collapse' + ${iter.index}" aria-expanded="false" th:aria-controls="'collapse' + ${iter.index}">
|
||||
<span th:utext="${trace.date}"/> | <span th:utext="${trace.path}"/>
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div th:id="'collapse' + ${iter.index}" class="panel-collapse collapse" role="tabpanel"
|
||||
th:aria-labelledby="'heading' + ${iter.index}">
|
||||
<div class="panel-body">
|
||||
<div>
|
||||
<pre th:utext="${trace.json}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user