Skip to content

Commit

Permalink
Merge pull request #14 from DolphFlynn/main
Browse files Browse the repository at this point in the history
Release 2.5
  • Loading branch information
Hannah-PortSwigger authored Jan 23, 2025
2 parents 3d3cfae + 3b1140a commit 04c355b
Show file tree
Hide file tree
Showing 87 changed files with 106,460 additions and 1,500 deletions.
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "weekly"
ignore:
- dependency-name: "com.nimbusds:nimbus-jose-jwt"
7 changes: 4 additions & 3 deletions .github/workflows/gradle-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ jobs:
java-version: '21'
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Test
uses: gradle/actions/setup-gradle@v3
with:
arguments: test
run: ./gradlew test

- name: Publish test report on failure
uses: actions/upload-artifact@v4
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ Additionally it facilitates several well-known attacks against JWT implementatio

## Changelog

**2.5 2025-01-13**
- Add ability to test for HMAC signatures using [weak secrets](https://github.com/wallarm/jwt-secrets).
- Add import capability for JWK data.
- Add support for decimal TimeClaims (Thanks to [@Nirusu](https://github.com/Nirusu)).
- Remember last used key within signing dialogs.

**2.4 2024-12-24**
- Add support for non-JSON claims within JWS (Thanks to [@Hannah-PortSwigger](https://github.com/Hannah-PortSwigger) for suggesting this).

Expand Down Expand Up @@ -150,6 +156,7 @@ The `Attack` option implements several well-known attacks against JSON Web Signa
* Signing with an empty HMAC key
* Signing with a *Psychic signature*
* Embedding a Collaborator payload
* Weak HMAC secret

These are described in more detail [below](#Attacks).

Expand All @@ -167,7 +174,7 @@ This option is automatically enabled if it is detected that the original JWT did
*JWT Editor* can be built from source.
* Ensure that Java JDK 21 or newer is installed
* From root of project, run the command `./gradlew jar`
* This should place the JAR file `jwt-editor-2.4.jar` within the `build/libs` directory
* This should place the JAR file `jwt-editor-2.5.jar` within the `build/libs` directory
* This can be loaded into Burp Suite by navigating to the `Extensions` tab, `Installed` sub-tab, clicking `Add` and loading the JAR file
* This BApp is using the newer Montoya API so it's best to use the latest version of Burp Suite (try the earlier adopter channel if there are issues with the latest stable release)

Expand Down Expand Up @@ -218,6 +225,9 @@ Burp Suite's [Collaborator](https://portswigger.net/burp/documentation/collabora
is fetching content based on the `x5u` or `jku` headers.
Note that this functionality is only available in Burp Suite Professional.

### Weak HMAC secret
Attempt to brute-force the signing key for JWS with HMAC signatures using known [JWT secrets](https://github.com/wallarm/jwt-secrets).

## Issues / Enhancements
If you have found a bug or think that a particular feature is missing, please raise an issue on the [GitHub repository](https://github.com/DolphFlynn/jwt-editor/issues).

Expand Down
10 changes: 5 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

group = 'com.blackberry'
version = '2.4'
version = '2.5'
description = 'jwt-editor'

repositories {
Expand Down Expand Up @@ -35,15 +35,15 @@ dependencies {
'com.nimbusds:nimbus-jose-jwt:9.21',
'org.exbin.deltahex:deltahex-swing:0.1.2',
'com.fifesoft:rsyntaxtextarea:3.5.3',
'org.json:json:20240303'
'org.json:json:20250107'
)
testImplementation(
"org.bouncycastle:bcprov-jdk18on:${bouncycastle_version}",
"org.bouncycastle:bcpkix-jdk18on:${bouncycastle_version}",
"net.portswigger.burp.extensions:montoya-api:${extender_version}",
'org.junit.jupiter:junit-jupiter:5.11.2',
'org.assertj:assertj-core:3.26.3',
'org.mockito:mockito-core:5.14.1'
'org.junit.jupiter:junit-jupiter:5.11.4',
'org.assertj:assertj-core:3.27.3',
'org.mockito:mockito-core:5.15.2'
)
}

Expand Down
8 changes: 3 additions & 5 deletions src/main/java/burp/JWTEditorExtension.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import com.blackberry.jwteditor.view.editor.WebSocketEditorView;
import com.blackberry.jwteditor.view.hexcodearea.HexCodeAreaFactory;
import com.blackberry.jwteditor.view.rsta.RstaFactory;
import com.blackberry.jwteditor.view.utils.ErrorLoggingActionListenerFactory;

import java.awt.*;

Expand Down Expand Up @@ -69,7 +68,6 @@ public void initialize(MontoyaApi api) {
userInterface.registerSuiteTab(suiteView.getTabCaption(), suiteView.getUiComponent());

HexCodeAreaFactory hexAreaCodeFactory = new HexCodeAreaFactory(api.logging(), api.userInterface());
ErrorLoggingActionListenerFactory actionListenerFactory = new ErrorLoggingActionListenerFactory(api.logging());
InformationPanelFactory informationPanelFactory = new InformationPanelFactory(api.userInterface(), api.logging());

userInterface.registerHttpRequestEditorProvider(editorCreationContext ->
Expand All @@ -78,7 +76,7 @@ public void initialize(MontoyaApi api) {
rstaFactory,
api.collaborator().defaultPayloadGenerator(),
hexAreaCodeFactory,
actionListenerFactory,
api.logging(),
informationPanelFactory,
editorCreationContext.editorMode() != READ_ONLY,
isProVersion
Expand All @@ -91,7 +89,7 @@ public void initialize(MontoyaApi api) {
rstaFactory,
api.collaborator().defaultPayloadGenerator(),
hexAreaCodeFactory,
actionListenerFactory,
api.logging(),
informationPanelFactory,
editorCreationContext.editorMode() != READ_ONLY,
isProVersion
Expand All @@ -104,7 +102,7 @@ public void initialize(MontoyaApi api) {
rstaFactory,
api.collaborator().defaultPayloadGenerator(),
hexAreaCodeFactory,
actionListenerFactory,
api.logging(),
informationPanelFactory,
editorCreationContext.editorMode() != READ_ONLY,
isProVersion
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
/*
Author : Dolph Flynn
Copyright 2024 Dolph Flynn
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.blackberry.jwteditor.exceptions;

public class SigningException extends Exception {
public SigningException(String msg) {
super(msg);
}

public SigningException(String message, Throwable cause) {
super(message, cause);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
/*
Author : Dolph Flynn
Copyright 2024 Dolph Flynn
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.blackberry.jwteditor.exceptions;

public class VerificationException extends Exception {
public VerificationException(String msg) {
super(msg);
}

public VerificationException(String message, Throwable cause) {
super(message, cause);
}
}
6 changes: 6 additions & 0 deletions src/main/java/com/blackberry/jwteditor/model/jose/Header.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

import static com.blackberry.jwteditor.utils.JSONUtils.isJsonCompact;
import static com.blackberry.jwteditor.utils.JSONUtils.prettyPrintJSON;
import static com.nimbusds.jose.HeaderParameterNames.ALGORITHM;

public class Header extends Base64Encoded {

Expand All @@ -44,4 +45,9 @@ public JSONObject json()
{
return new JSONObject(decoded());
}

public String algorithm() {
JSONObject json = json();
return json.has(ALGORITHM) ? json.getString(ALGORITHM) : "";
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/blackberry/jwteditor/model/jose/JWE.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.nimbusds.jose.JWEDecrypter;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jose.util.Base64URL;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.security.Provider;
import java.security.Security;
Expand Down Expand Up @@ -124,7 +125,7 @@ public JWS decrypt(Key key) throws DecryptionException, ParseException {
JWEDecrypter decrypter = key.getDecrypter(header.getAlgorithm());

// Try to use the BouncyCastle provider, but fall-back to default if this fails
Provider provider = Security.getProvider("BC");
Provider provider = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
if (provider != null) {
decrypter.getJCAContext().setProvider(provider);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.blackberry.jwteditor.model.keys.Key;
import com.nimbusds.jose.*;
import com.nimbusds.jose.util.Base64URL;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.nio.charset.StandardCharsets;
import java.security.Provider;
Expand All @@ -44,7 +45,7 @@ public static JWE encrypt(JWS jws, Key key, JWEAlgorithm kek, EncryptionMethod c
}

// Try to use the BouncyCastle provider, but fall-back to default if this fails
Provider provider = Security.getProvider("BC");
Provider provider = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
if (provider != null) {
encrypter.getJCAContext().setProvider(provider);
}
Expand Down
21 changes: 4 additions & 17 deletions src/main/java/com/blackberry/jwteditor/model/jose/JWS.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
import com.nimbusds.jose.util.Base64URL;

import java.nio.charset.StandardCharsets;
import java.security.Provider;
import java.security.Security;
import java.util.List;

import static com.blackberry.jwteditor.model.jose.JWSVerifierFactory.verifierFor;

/**
* Class representing a JWS
*/
Expand All @@ -53,8 +53,7 @@ public JWSClaims claims() {
return claims;
}

public Signature signature()
{
public Signature signature() {
return signature;
}

Expand Down Expand Up @@ -84,19 +83,7 @@ public List<Information> information() {
* @throws VerificationException if verification process fails
*/
public boolean verify(Key key, JWSHeader verificationInfo) throws VerificationException {
// Get the verifier based on the key type
JWSVerifier verifier;
try {
verifier = key.getVerifier();
} catch (JOSEException e) {
throw new VerificationException(e.getMessage());
}

// Try to use the BouncyCastle provider, but fall-back to default if this fails
Provider provider = Security.getProvider("BC");
if (provider != null) {
verifier.getJCAContext().setProvider(provider);
}
JWSVerifier verifier = verifierFor(key, verificationInfo.getAlgorithm());

// Build the signing input
// JWS signature input is the ASCII bytes of the base64 encoded header and payload concatenated with a '.'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import java.text.ParseException;

import static com.blackberry.jwteditor.model.jose.JWSSignerFactory.signerFor;
import static com.blackberry.jwteditor.utils.StringUtils.countOccurrences;
import static com.nimbusds.jose.HeaderParameterNames.*;
import static java.util.Arrays.stream;
Expand Down Expand Up @@ -83,7 +84,7 @@ public static JWS sign(Key key, JWSAlgorithm algorithm, SigningUpdateMode update
}

public static JWS sign(Key key, JWSAlgorithm algorithm, Base64URL header, Base64URL payload) throws SigningException {
return new JWSSigner(key).sign(header, payload, new JWSHeader.Builder(algorithm).build());
return signerFor(key, algorithm).sign(header, payload, new JWSHeader.Builder(algorithm).build());
}

/**
Expand Down
19 changes: 2 additions & 17 deletions src/main/java/com/blackberry/jwteditor/model/jose/JWSSigner.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,17 @@
package com.blackberry.jwteditor.model.jose;

import com.blackberry.jwteditor.exceptions.SigningException;
import com.blackberry.jwteditor.model.keys.Key;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.util.Base64URL;

import java.nio.charset.StandardCharsets;
import java.security.Provider;
import java.security.Security;

class JWSSigner {
private final com.nimbusds.jose.JWSSigner signer;

JWSSigner(Key key) throws SigningException {
// Get the signer based on the key type
try {
signer = key.getSigner();
} catch (JOSEException e) {
throw new SigningException(e.getMessage());
}

// Try to use the BouncyCastle provider, but fall-back to default if this fails
Provider provider = Security.getProvider("BC");

if (provider != null) {
signer.getJCAContext().setProvider(provider);
}
JWSSigner(com.nimbusds.jose.JWSSigner signer) {
this.signer = signer;
}

public JWS sign(Base64URL header, Base64URL payload, JWSHeader signingInfo) throws SigningException {
Expand Down
Loading

0 comments on commit 04c355b

Please sign in to comment.