More JWT work
This commit is contained in:
parent
7a0820bf89
commit
9d7886d572
@ -81,6 +81,39 @@ public class CreateDB {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description of the Method
|
||||
*
|
||||
* @param connection Description of the Parameter
|
||||
* @throws SQLException Description of the Exception
|
||||
*/
|
||||
private void createJWTKeys(Connection connection) throws SQLException {
|
||||
Statement statement = connection.createStatement();
|
||||
|
||||
// Drop servers table
|
||||
try {
|
||||
String dropTable = "DROP TABLE jwt_keys";
|
||||
statement.executeUpdate(dropTable);
|
||||
} catch (SQLException e) {
|
||||
System.out.println("Info - Could not drop jwtkeys table");
|
||||
}
|
||||
|
||||
// Create the new table
|
||||
try {
|
||||
String createTableStatement = "CREATE TABLE jwt_keys"
|
||||
+ " (" + "id varchar(10),"
|
||||
+ "key varchar(20))";
|
||||
statement.executeUpdate(createTableStatement);
|
||||
|
||||
String insertData1 = "INSERT INTO jwt_keys VALUES ('webgoat_key', 'qwertyqwerty1234')";
|
||||
String insertData2 = "INSERT INTO jwt_keys VALUES ('webwolf_key', 'doesnotreallymatter')";
|
||||
statement.executeUpdate(insertData1);
|
||||
statement.executeUpdate(insertData2);
|
||||
} catch (SQLException e) {
|
||||
System.out.println("Error creating product table " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Description of the Method
|
||||
@ -975,6 +1008,7 @@ public class CreateDB {
|
||||
createTanTable(connection);
|
||||
createMFEImagesTable(connection);
|
||||
createModifyWithSQLLessonTable(connection);
|
||||
createJWTKeys(connection);
|
||||
System.out.println("Success: creating tables.");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,85 @@
|
||||
package org.owasp.webgoat.plugin;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import io.jsonwebtoken.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentHints;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.session.DatabaseUtilities;
|
||||
import org.owasp.webgoat.session.WebSession;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/23/17.
|
||||
*/
|
||||
@AssignmentPath("/JWT/final")
|
||||
@AssignmentHints({"jwt-final-hint1", "jwt-final-hint2", "jwt-final-hint3", "jwt-final-hint4", "jwt-final-hint5", "jwt-final-hint6"})
|
||||
public class JWTFinalEndpoint extends AssignmentEndpoint {
|
||||
|
||||
@Autowired
|
||||
private WebSession webSession;
|
||||
|
||||
@PostMapping("follow/{user}")
|
||||
public @ResponseBody
|
||||
String follow(@PathVariable("user") String user) {
|
||||
if ("Jerry".equals(user)) {
|
||||
return "Following yourself seems redundant";
|
||||
} else {
|
||||
return "You are now following Tom";
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("delete")
|
||||
public @ResponseBody
|
||||
AttackResult resetVotes(@RequestParam("token") String token) {
|
||||
if (StringUtils.isEmpty(token)) {
|
||||
return trackProgress(failed().feedback("jwt-invalid-token").build());
|
||||
} else {
|
||||
try {
|
||||
final String[] errorMessage = {null};
|
||||
Jwt jwt = Jwts.parser().setSigningKeyResolver(new SigningKeyResolverAdapter() {
|
||||
@Override
|
||||
public byte[] resolveSigningKeyBytes(JwsHeader header, Claims claims) {
|
||||
final String kid = (String) header.get("kid");
|
||||
try {
|
||||
Connection connection = DatabaseUtilities.getConnection(webSession);
|
||||
ResultSet rs = connection.createStatement().executeQuery("SELECT key FROM jwt_keys WHERE id = " + kid);
|
||||
while (rs.next()) {
|
||||
return rs.getString(1).getBytes(Charsets.UTF_8);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
errorMessage[0] = e.getMessage();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}).parse(token);
|
||||
if (errorMessage[0] != null) {
|
||||
return trackProgress(failed().output(errorMessage[0]).build());
|
||||
}
|
||||
Claims claims = (Claims) jwt.getBody();
|
||||
String username = (String) claims.get("username");
|
||||
if ("Jerry".equals(username)) {
|
||||
return trackProgress(failed().feedback("jwt-final-jerry-account").build());
|
||||
}
|
||||
if ("Tom".equals(username)) {
|
||||
return trackProgress(success().build());
|
||||
} else {
|
||||
return trackProgress(failed().feedback("jwt-final-not-tom").build());
|
||||
}
|
||||
} catch (JwtException e) {
|
||||
return trackProgress(failed().feedback("jwt-invalid-token").output(e.toString()).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.owasp.webgoat.plugin.refresh;
|
||||
|
||||
public class RefreshEndpoint {
|
||||
|
||||
private static final String TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE0OTUyODU3NDUsImV4cCI6MTQ5NTI4NTc0NSwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJ0b21Ad2ViZ29hdC5vcmciLCJuYW1lIjoiVG9tIiwiZW1haWwiOiJ0b21Ad2ViZ29hdC5jb20iLCJyb2xlIjoiQ2F0In0.NTd3E17JZlVKZk52Wq_AWZ0RDafV5KDRMuJner_zUn4";
|
||||
private static final String JWT_KEY = "qwertyuiopasdfghjklzxcvbnm123456";
|
||||
|
||||
|
||||
}
|
@ -9,4 +9,108 @@ a.list-group-item.active small {
|
||||
}
|
||||
.img-responsive {
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.card {
|
||||
font-size: 1em;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
border: none;
|
||||
border-radius: .28571429rem;
|
||||
box-shadow: 0 1px 3px 0 #d4d4d5, 0 0 0 1px #d4d4d5;
|
||||
}
|
||||
|
||||
.card-block {
|
||||
font-size: 1em;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
border: none;
|
||||
border-top: 1px solid rgba(34, 36, 38, .1);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.card-img-top {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 1.28571429em;
|
||||
font-weight: 700;
|
||||
line-height: 1.2857em;
|
||||
}
|
||||
|
||||
.card-text {
|
||||
clear: both;
|
||||
margin-top: .5em;
|
||||
color: rgba(0, 0, 0, .68);
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
font-size: 1em;
|
||||
position: static;
|
||||
top: 0;
|
||||
left: 0;
|
||||
max-width: 100%;
|
||||
padding: .75em 1em;
|
||||
color: rgba(0, 0, 0, .4);
|
||||
border-top: 1px solid rgba(0, 0, 0, .05) !important;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.card-inverse .btn {
|
||||
border: 1px solid rgba(0, 0, 0, .05);
|
||||
}
|
||||
|
||||
.profile {
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.profile-avatar {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.profile-inline {
|
||||
position: relative;
|
||||
top: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.profile-inline ~ .card-title {
|
||||
display: inline-block;
|
||||
margin-left: 4px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.text-bold {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.meta {
|
||||
font-size: 1em;
|
||||
color: rgba(0, 0, 0, .4);
|
||||
}
|
||||
|
||||
.meta a {
|
||||
text-decoration: none;
|
||||
color: rgba(0, 0, 0, .4);
|
||||
}
|
||||
|
||||
.meta a:hover {
|
||||
color: rgba(0, 0, 0, .87);
|
||||
}
|
@ -106,11 +106,11 @@
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:JWT_refresh_assignment"></div>
|
||||
<div class="adoc-content" th:replace="doc:JWT_refresh_assignment.adoc"></div>
|
||||
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/jwt.css}"/>
|
||||
<script th:src="@{/lesson_js/bootstrap.min.js}" language="JavaScript"></script>
|
||||
<script th:src="@{/lesson_js/jwt-signing.js}" language="JavaScript"></script>
|
||||
<script th:src="@{/lesson_js/jwt-final.js}" language="JavaScript"></script>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
@ -119,44 +119,97 @@
|
||||
action="/WebGoat/JWT/refresh/reset"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="well">
|
||||
<div class="pull-right">
|
||||
<div class="dropdown">
|
||||
<button type="button" data-toggle="dropdown" class="btn btn-default dropdown-toggle"
|
||||
title="Change user">
|
||||
<i class="fa fa-user"></i> <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-left">
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||
onclick="javascript:login('Guest')"
|
||||
th:text="Guest">current</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||
onclick="javascript:login('Tom')"
|
||||
th:text="Tom">current</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||
onclick="javascript:login('Jerry')"
|
||||
th:text="Jerry">current</a></li>
|
||||
<li role="presentation"><a role="menuitem" tabindex="-1"
|
||||
onclick="javascript:login('Sylvester')"
|
||||
th:text="Sylvester">current</a></li>
|
||||
</ul>
|
||||
<button type="button" class="btn btn-default fa fa-refresh" title="Refresh votes"
|
||||
onclick="javascript:getVotings()"/>
|
||||
<button type="submit" class="btn btn-default fa fa-trash-o" title="Reset votes"/>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-right">Welcome back, <b><span id="name"></span></b></p>
|
||||
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
|
||||
<div class="card card-inverse card-info">
|
||||
<img th:src="@{/images/jerry.png}" class="card-img-top"></img>
|
||||
<div class="card-block">
|
||||
<figure class="profile profile-inline">
|
||||
<img th:src="@{/images/jerry.png}" class="profile-avatar" alt=""></img>
|
||||
</figure>
|
||||
<h4 class="card-title">Jerry</h4>
|
||||
<div class="card-text">
|
||||
Jerry is a small, brown, house mouse.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Vote for your favorite</h3>
|
||||
<div class="card-footer">
|
||||
<small>Last updated 12 minutes ago</small>
|
||||
<button class="btn btn-info float-right btn-sm">Follow</button>
|
||||
</div>
|
||||
<div id="votesList" class="list-group">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
|
||||
<div class="card card-inverse card-info">
|
||||
<img th:src="@{/images/tom.png}" class="card-img-top"></img>
|
||||
<div class="card-block">
|
||||
<figure class="profile profile-inline">
|
||||
<img th:src="@{/images/tom.png}" class="profile-avatar" alt=""></img>
|
||||
</figure>
|
||||
<h4 class="card-title">Tom</h4>
|
||||
<div class="card-text">
|
||||
Tom is a grey and white domestic short hair cat.
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<small>Last updated 12 days ago</small>
|
||||
<button class="btn btn-info float-right btn-sm">Follow</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:JWT_final.adoc"></div>
|
||||
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/jwt.css}"/>
|
||||
<script th:src="@{/lesson_js/bootstrap.min.js}" language="JavaScript"></script>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST"
|
||||
action="/WebGoat/JWT/final/delete?token=eyJ0eXAiOiJKV1QiLCJraWQiOiJ3ZWJnb2F0X2tleSIsImFsZyI6IkhTMjU2In0.eyJpc3MiOiJXZWJHb2F0IFRva2VuIEJ1aWxkZXIiLCJpYXQiOjE1MjQyMTA5MDQsImV4cCI6MTYxODkwNTMwNCwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJqZXJyeUB3ZWJnb2F0LmNvbSIsInVzZXJuYW1lIjoiSmVycnkiLCJFbWFpbCI6ImplcnJ5QHdlYmdvYXQuY29tIiwiUm9sZSI6WyJDYXQiXX0.CgZ27DzgVW8gzc0n6izOU638uUCi6UhiOJKYzoEZGE8"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
<div class="container-fluid">
|
||||
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
|
||||
<div class="card card-inverse card-info">
|
||||
<img th:src="@{/images/jerry.png}" class="card-img-top"></img>
|
||||
<div class="card-block">
|
||||
<figure class="profile profile-inline">
|
||||
<img th:src="@{/images/jerry.png}" class="profile-avatar" alt=""></img>
|
||||
</figure>
|
||||
<h4 class="card-title">Jerry</h4>
|
||||
<div class="card-text">
|
||||
Jerry is a small, brown, house mouse.
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<small>Last updated 12 minutes ago</small>
|
||||
<button class="btn btn-info float-right btn-sm">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
|
||||
<div class="card card-inverse card-info">
|
||||
<img th:src="@{/images/tom.png}" class="card-img-top"></img>
|
||||
<div class="card-block">
|
||||
<figure class="profile profile-inline">
|
||||
<img th:src="@{/images/tom.png}" class="profile-avatar" alt=""></img>
|
||||
</figure>
|
||||
<h4 class="card-title">Tom</h4>
|
||||
<div class="card-text">
|
||||
Tom is a grey and white domestic short hair cat.
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<small>Last updated 12 days ago</small>
|
||||
<button class="btn btn-info float-right btn-sm" onclick="javascript:follow('Tom')">Follow</button>
|
||||
<button class="btn btn-info float-right btn-sm">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -13,3 +13,13 @@ jwt-change-token-hint5=Submit the token by changing the algorithm to None and re
|
||||
jwt-secret-hint1=Save the token and try to verify the token locally
|
||||
jwt-secret-hint2=Download a word list dictionary (https://github.com/first20hours/google-10000-english)
|
||||
jwt-secret-hint3=Write a small program or use HashCat for brute forcing the token according the word list
|
||||
|
||||
jwt-final-jerry-account=Yikes, you are removing Jerry's account, try to delete the account of Tom
|
||||
jwt-final-not-tom=Username is not Tom try to pass a token for Tom
|
||||
|
||||
jwt-final-hint1=Take a look at the token and specifically and the header
|
||||
jwt-final-hint2=The 'kid' (key ID) header parameter is a hint indicating which key was used to secure the JWS
|
||||
jwt-final-hint3=The key can be located on the filesystem in memory or even reside in the database
|
||||
jwt-final-hint4=The key is stored in the database and loaded while verifying a token
|
||||
jwt-final-hint5=Using a SQL injection you might be able to manipulate the key to something you know and create a new token.
|
||||
jwt-final-hint6=Use: key1' union all select 'abcdefg' limit 1,1 -- And change the contents of the token to Tom and hit the endpoint with the new token
|
BIN
webgoat-lessons/jwt/src/main/resources/images/jerry.png
Normal file
BIN
webgoat-lessons/jwt/src/main/resources/images/jerry.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 100 KiB |
6
webgoat-lessons/jwt/src/main/resources/images/logs.txt
Normal file
6
webgoat-lessons/jwt/src/main/resources/images/logs.txt
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /statuses/605086114483826688/favorite?authenticity_token=264c8bf11e0212227c001b77543c3519 HTTP/1.1" 404 242 "-" "Go-http-client/1.1" "-"
|
||||
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /images/phocagallery/almhuette/thumbs/phoca_thumb_l_zimmer.jpg HTTP/1.1" 200 12783 "-" "Go-http-client/1.1" "-"
|
||||
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /signup HTTP/1.1" 404 212 "-" "Go-http-client/1.1" "-"
|
||||
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /vsmartseo/status/605086114483826688/actions HTTP/1.1" 404 249 "-" "Go-http-client/1.1" "-"
|
||||
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /vsmartseo?p=s HTTP/1.1" 404 215 "-" "Go-http-client/1.1" "-"
|
BIN
webgoat-lessons/jwt/src/main/resources/images/tom.png
Normal file
BIN
webgoat-lessons/jwt/src/main/resources/images/tom.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 217 KiB |
10
webgoat-lessons/jwt/src/main/resources/js/jwt-final.js
Normal file
10
webgoat-lessons/jwt/src/main/resources/js/jwt-final.js
Normal file
@ -0,0 +1,10 @@
|
||||
function follow(user) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'JWT/final/follow/' + user
|
||||
}).then(function (result) {
|
||||
$("#toast").setTextContent(result);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
== Final challenges
|
||||
|
||||
Same as before try to change the token and become admin, this assignment requires multiple attack scenarios.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
=== Assignment
|
||||
|
||||
In this assignment Tom no longer has a valid token, try to find a way to create a new access token and use that token
|
||||
to vote.
|
||||
Jerry really wants to follow Tom, can you help him to follow Jerry?
|
||||
From a breach of last year the following logfile is available link:images/logs.txt[here]
|
||||
|
||||
|
||||
|
@ -13,7 +13,7 @@ to be aware of before validating the token.
|
||||
|
||||
== Assignment
|
||||
|
||||
Try to change the token you receive and become an admin user by changing the token.
|
||||
Try to change the token you receive and become an admin user by changing the token and once you are admin reset the votes
|
||||
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user