diff --git a/src/main/java/burp/intruder/JWSPayloadProcessor.java b/src/main/java/burp/intruder/JWSPayloadProcessor.java index 706772e..2810732 100644 --- a/src/main/java/burp/intruder/JWSPayloadProcessor.java +++ b/src/main/java/burp/intruder/JWSPayloadProcessor.java @@ -11,6 +11,7 @@ import com.blackberry.jwteditor.model.jose.JWSFactory; import com.blackberry.jwteditor.model.keys.Key; import com.blackberry.jwteditor.model.keys.KeysModel; +import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.util.Base64URL; import org.json.JSONObject; @@ -18,6 +19,7 @@ import static burp.intruder.FuzzLocation.PAYLOAD; import static com.blackberry.jwteditor.model.jose.JOSEObjectFinder.parseJOSEObject; +import static com.nimbusds.jose.HeaderParameterNames.ALGORITHM; public class JWSPayloadProcessor implements PayloadProcessor { private final Logging logging; @@ -83,8 +85,20 @@ private JWS createJWS(Base64URL header, Base64URL payload, Base64URL originalSig return loadKey() .flatMap(key -> { try { - // TODO - update alg within header - return Optional.of(JWSFactory.sign(key, intruderConfig.signingAlgorithm(), header, payload)); + JWSAlgorithm algorithm = intruderConfig.signingAlgorithm(); + + String headerJson = header.decodeToString(); + JSONObject headerJsonObject = new JSONObject(headerJson); + + Object originalAlgorithm = headerJsonObject.get(ALGORITHM); + headerJsonObject.put(ALGORITHM, algorithm.getName()); + + // Only update when alg different to preserve key order + Base64URL updatedHeader = originalAlgorithm instanceof JWSAlgorithm alg && alg.equals(algorithm) + ? header + : Base64URL.encode(headerJsonObject.toString()); + + return Optional.of(JWSFactory.sign(key, algorithm, updatedHeader, payload)); } catch (SigningException ex) { logging.logToError("Failed to sign JWS: " + ex); return Optional.empty(); diff --git a/src/test/java/burp/intruder/JWSPayloadProcessorTest.java b/src/test/java/burp/intruder/JWSPayloadProcessorTest.java index c600a67..5aa8f60 100644 --- a/src/test/java/burp/intruder/JWSPayloadProcessorTest.java +++ b/src/test/java/burp/intruder/JWSPayloadProcessorTest.java @@ -21,6 +21,7 @@ import static burp.intruder.FuzzLocation.PAYLOAD; import static burp.intruder.IntruderConfigBuilder.intruderConfig; import static com.blackberry.jwteditor.KeysModelBuilder.keysModel; +import static com.nimbusds.jose.JWSAlgorithm.RS256; import static com.nimbusds.jose.JWSAlgorithm.RS512; import static data.PemData.RSA1024Private; import static org.assertj.core.api.Assertions.assertThat; @@ -167,4 +168,24 @@ void givenBaseValueJWSAndFuzzParameterPresentInPayload_whenResignOnAndSigningKey assertThat(result.action()).isEqualTo(USE_PAYLOAD); assertThat(result.processedPayload().toString()).isEqualTo("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImVtYW5vbiIsImlhdCI6MTUxNjIzOTAyMn0.poPOxqjqp-CnC2b7eaf2QvfvAfawzp6k-P1QECIHN7KCTnFIlQbiJC4ZtLPH_0-o3HQcUGZbib3m1CVWeY21FIUTVUmOyjU8XuBohtBXRlXoaKXVWibrm5YiLC3yNQz5uAF-gdBB8ybvsmetK7JIZ8UvQdJ3mdvlAAW-3xFv8fs"); } + + @Test + void givenBaseValueJWSAndFuzzParameterPresentInPayload_whenResignOnAndSigningKeyPresentAndAlgorithmChanged_thenPayloadAndAlgModifiedAndResigned() { + String baseValue = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImNyZXMiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + PayloadData payloadData = payloadData().withBaseValue(baseValue).withCurrentPayload("emanon").build(); + KeysModel keysModel = keysModel().withRSAKey(RSA1024Private, KEY_ID).build(); + IntruderConfig intruderConfig = intruderConfig() + .withFuzzParameter("name") + .withFuzzLocation(PAYLOAD) + .withSigningKeyId(KEY_ID) + .withSigningAlgorithm(RS256) + .withResigning(true) + .build(); + + JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig, LOGGING, keysModel); + PayloadProcessingResult result = processor.processPayload(payloadData); + + assertThat(result.action()).isEqualTo(USE_PAYLOAD); + assertThat(result.processedPayload().toString()).isEqualTo("eyJraWQiOiJjcmVzIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImVtYW5vbiIsImlhdCI6MTUxNjIzOTAyMn0.qZw9QLyX5NAxBioegUsiBoWVpVShdy1EGHwwgOtknyVXhXqQDbXt15IYUkj66_dDIGNuZ76g_BdJLy9V9qG-sTbQgsLykbfLfdqelNhOsw-c_gs7eJPK0DYaYmBZNJayD5EJoOTF0Vs0AR2Rlnhf1PeoK04HZfJhoDS39gs4hRU"); + } } \ No newline at end of file