From 34661eb189f8611b651ef6dcf3efd2ccb061fb4d Mon Sep 17 00:00:00 2001 From: Dolph Flynn <96876199+DolphFlynn@users.noreply.github.com> Date: Sun, 25 Feb 2024 13:16:35 +0000 Subject: [PATCH 1/2] Create IntruderConfigBuilder and use with KeysModelBuilder within JWSPayloadProcessorTest. --- .../burp/intruder/IntruderConfigBuilder.java | 27 ++++++++++++++++ .../intruder/JWSPayloadProcessorTest.java | 31 ++++++++----------- .../jwteditor/KeysModelBuilder.java | 14 ++++----- 3 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 src/test/java/burp/intruder/IntruderConfigBuilder.java diff --git a/src/test/java/burp/intruder/IntruderConfigBuilder.java b/src/test/java/burp/intruder/IntruderConfigBuilder.java new file mode 100644 index 0000000..7dc40d9 --- /dev/null +++ b/src/test/java/burp/intruder/IntruderConfigBuilder.java @@ -0,0 +1,27 @@ +package burp.intruder; + +class IntruderConfigBuilder { + private final IntruderConfig config; + + private IntruderConfigBuilder() { + this.config = new IntruderConfig(); + } + + IntruderConfigBuilder withFuzzLocation(FuzzLocation fuzzLocation) { + config.setFuzzLocation(fuzzLocation); + return this; + } + + IntruderConfigBuilder withFuzzParameter(String parameterName) { + config.setFuzzParameter(parameterName); + return this; + } + + IntruderConfig build() { + return config; + } + + static IntruderConfigBuilder intruderConfig() { + return new IntruderConfigBuilder(); + } +} diff --git a/src/test/java/burp/intruder/JWSPayloadProcessorTest.java b/src/test/java/burp/intruder/JWSPayloadProcessorTest.java index e800908..79e9126 100644 --- a/src/test/java/burp/intruder/JWSPayloadProcessorTest.java +++ b/src/test/java/burp/intruder/JWSPayloadProcessorTest.java @@ -19,6 +19,8 @@ import static burp.api.montoya.logging.StubLogging.LOGGING; import static burp.intruder.FuzzLocation.HEADER; import static burp.intruder.FuzzLocation.PAYLOAD; +import static burp.intruder.IntruderConfigBuilder.intruderConfig; +import static com.blackberry.jwteditor.KeysModelBuilder.keysModel; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -26,6 +28,7 @@ @ExtendWith(MontoyaExtension.class) class JWSPayloadProcessorTest { + private static final KeysModel EMPTY_KEYS_MODEL = keysModel().build(); @BeforeEach void configureMocks() { @@ -42,9 +45,9 @@ void configureMocks() { void givenBaseValueNotJWS_whenPayloadProcessed_thenPayloadLeftUnchanged() { String baseValue = "isogeny"; PayloadData payloadData = payloadData().withBaseValue(baseValue).build(); - KeysModel keysModel = new KeysModel(); - JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig("role", PAYLOAD), LOGGING, keysModel); + IntruderConfig intruderConfig = intruderConfig().withFuzzParameter("role").withFuzzLocation(PAYLOAD).build(); + JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig, LOGGING, EMPTY_KEYS_MODEL); PayloadProcessingResult result = processor.processPayload(payloadData); assertThat(result.action()).isEqualTo(USE_PAYLOAD); @@ -55,9 +58,9 @@ void givenBaseValueNotJWS_whenPayloadProcessed_thenPayloadLeftUnchanged() { void givenBaseValueJWSAndFuzzParameterNotPresent_whenPayloadProcessed_thenPayloadLeftUnchanged() { String baseValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; PayloadData payloadData = payloadData().withBaseValue(baseValue).build(); - KeysModel keysModel = new KeysModel(); - JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig("role", PAYLOAD), LOGGING, keysModel); + IntruderConfig intruderConfig = intruderConfig().withFuzzParameter("role").withFuzzLocation(PAYLOAD).build(); + JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig, LOGGING, EMPTY_KEYS_MODEL); PayloadProcessingResult result = processor.processPayload(payloadData); assertThat(result.action()).isEqualTo(USE_PAYLOAD); @@ -68,9 +71,9 @@ void givenBaseValueJWSAndFuzzParameterNotPresent_whenPayloadProcessed_thenPayloa void givenBaseValueJWSAndFuzzParameterPresentInWrongContext_whenPayloadProcessed_thenPayloadLeftUnchanged() { String baseValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; PayloadData payloadData = payloadData().withBaseValue(baseValue).build(); - KeysModel keysModel = new KeysModel(); - JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig("alg", PAYLOAD), LOGGING, keysModel); + IntruderConfig intruderConfig = intruderConfig().withFuzzParameter("alg").withFuzzLocation(PAYLOAD).build(); + JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig, LOGGING, EMPTY_KEYS_MODEL); PayloadProcessingResult result = processor.processPayload(payloadData); assertThat(result.action()).isEqualTo(USE_PAYLOAD); @@ -81,9 +84,9 @@ void givenBaseValueJWSAndFuzzParameterPresentInWrongContext_whenPayloadProcessed void givenBaseValueJWSAndFuzzParameterPresentInHeader_whenPayloadProcessed_thenPayloadModified() { String baseValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; PayloadData payloadData = payloadData().withBaseValue(baseValue).withCurrentPayload("RS256").build(); - KeysModel keysModel = new KeysModel(); - JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig("alg", HEADER), LOGGING, keysModel); + IntruderConfig intruderConfig = intruderConfig().withFuzzParameter("alg").withFuzzLocation(HEADER).build(); + JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig, LOGGING, EMPTY_KEYS_MODEL); PayloadProcessingResult result = processor.processPayload(payloadData); assertThat(result.action()).isEqualTo(USE_PAYLOAD); @@ -94,20 +97,12 @@ void givenBaseValueJWSAndFuzzParameterPresentInHeader_whenPayloadProcessed_thenP void givenBaseValueJWSAndFuzzParameterPresentInPayload_whenPayloadProcessed_thenPayloadModified() { String baseValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; PayloadData payloadData = payloadData().withBaseValue(baseValue).withCurrentPayload("emanon").build(); - KeysModel keysModel = new KeysModel(); - JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig("name", PAYLOAD), LOGGING, keysModel); + IntruderConfig intruderConfig = intruderConfig().withFuzzParameter("name").withFuzzLocation(PAYLOAD).build(); + JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig, LOGGING, EMPTY_KEYS_MODEL); PayloadProcessingResult result = processor.processPayload(payloadData); assertThat(result.action()).isEqualTo(USE_PAYLOAD); assertThat(result.processedPayload().toString()).isEqualTo("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImVtYW5vbiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"); } - - private static IntruderConfig intruderConfig(String parameterName, FuzzLocation parameterLocation) { - IntruderConfig intruderConfig = new IntruderConfig(); - intruderConfig.setFuzzParameter(parameterName); - intruderConfig.setFuzzLocation(parameterLocation); - - return intruderConfig; - } } \ No newline at end of file diff --git a/src/test/java/com/blackberry/jwteditor/KeysModelBuilder.java b/src/test/java/com/blackberry/jwteditor/KeysModelBuilder.java index 054e9d5..b017ac1 100644 --- a/src/test/java/com/blackberry/jwteditor/KeysModelBuilder.java +++ b/src/test/java/com/blackberry/jwteditor/KeysModelBuilder.java @@ -25,31 +25,31 @@ import static com.blackberry.jwteditor.KeyLoader.*; -class KeysModelBuilder { +public class KeysModelBuilder { private final AtomicInteger keyId = new AtomicInteger(); private final KeysModel model = new KeysModel(); - KeysModelBuilder withECKey(String pem) { + public KeysModelBuilder withECKey(String pem) { model.addKey(loadECKey(pem, nextKeyId())); return this; } - KeysModelBuilder withRSAKey(String pem) { + public KeysModelBuilder withRSAKey(String pem) { model.addKey(loadRSAKey(pem, nextKeyId())); return this; } - KeysModelBuilder withOKPKey(String pem) { + public KeysModelBuilder withOKPKey(String pem) { model.addKey(loadOKPKey(pem, nextKeyId())); return this; } - KeysModelBuilder withKey(Key key) { + public KeysModelBuilder withKey(Key key) { model.addKey(key); return this; } - KeysModel build() { + public KeysModel build() { return model; } @@ -57,7 +57,7 @@ private String nextKeyId() { return Integer.toString(keyId.incrementAndGet()); } - static KeysModelBuilder keysModel() { + public static KeysModelBuilder keysModel() { return new KeysModelBuilder(); } } From 0d108d7e5daef12ba5af1399cc810da5f6921fcb Mon Sep 17 00:00:00 2001 From: Dolph Flynn <96876199+DolphFlynn@users.noreply.github.com> Date: Sun, 25 Feb 2024 14:28:06 +0000 Subject: [PATCH 2/2] Add tests for resigning of Intruder payloads during fuzzing. --- .../burp/intruder/JWSPayloadProcessor.java | 25 ++++---- .../burp/intruder/IntruderConfigBuilder.java | 17 +++++ .../intruder/JWSPayloadProcessorTest.java | 62 +++++++++++++++++++ .../jwteditor/KeysModelBuilder.java | 18 +++++- 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/src/main/java/burp/intruder/JWSPayloadProcessor.java b/src/main/java/burp/intruder/JWSPayloadProcessor.java index 11cda73..706772e 100644 --- a/src/main/java/burp/intruder/JWSPayloadProcessor.java +++ b/src/main/java/burp/intruder/JWSPayloadProcessor.java @@ -80,17 +80,18 @@ public String displayName() { // Creates a JWS object from the given attributes. Signs the JWS if possible (i.e., available key selected in Intruder settings) private JWS createJWS(Base64URL header, Base64URL payload, Base64URL originalSignature) { - return this.loadKey().flatMap(key -> { - Optional result = Optional.empty(); - - try { - // TODO - update alg within header - result = Optional.of(JWSFactory.sign(key, intruderConfig.signingAlgorithm(), header, payload)); - } catch (SigningException ex) { - logging.logToError("Failed to sign JWS: " + ex); - } - - return result; - }).orElseGet(() -> JWSFactory.jwsFromParts(header, payload, originalSignature)); + return loadKey() + .flatMap(key -> { + try { + // TODO - update alg within header + return Optional.of(JWSFactory.sign(key, intruderConfig.signingAlgorithm(), header, payload)); + } catch (SigningException ex) { + logging.logToError("Failed to sign JWS: " + ex); + return Optional.empty(); + } + }) + .orElseGet( + () -> JWSFactory.jwsFromParts(header, payload, originalSignature) + ); } } diff --git a/src/test/java/burp/intruder/IntruderConfigBuilder.java b/src/test/java/burp/intruder/IntruderConfigBuilder.java index 7dc40d9..741849f 100644 --- a/src/test/java/burp/intruder/IntruderConfigBuilder.java +++ b/src/test/java/burp/intruder/IntruderConfigBuilder.java @@ -1,5 +1,7 @@ package burp.intruder; +import com.nimbusds.jose.JWSAlgorithm; + class IntruderConfigBuilder { private final IntruderConfig config; @@ -17,6 +19,21 @@ IntruderConfigBuilder withFuzzParameter(String parameterName) { return this; } + IntruderConfigBuilder withSigningKeyId(String signingId) { + config.setSigningKeyId(signingId); + return this; + } + + IntruderConfigBuilder withSigningAlgorithm(JWSAlgorithm algorithm) { + config.setSigningAlgorithm(algorithm); + return this; + } + + IntruderConfigBuilder withResigning(boolean resign) { + config.setResign(resign); + return this; + } + IntruderConfig build() { return config; } diff --git a/src/test/java/burp/intruder/JWSPayloadProcessorTest.java b/src/test/java/burp/intruder/JWSPayloadProcessorTest.java index 79e9126..c600a67 100644 --- a/src/test/java/burp/intruder/JWSPayloadProcessorTest.java +++ b/src/test/java/burp/intruder/JWSPayloadProcessorTest.java @@ -21,6 +21,8 @@ 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.RS512; +import static data.PemData.RSA1024Private; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -29,6 +31,7 @@ @ExtendWith(MontoyaExtension.class) class JWSPayloadProcessorTest { private static final KeysModel EMPTY_KEYS_MODEL = keysModel().build(); + private static final String KEY_ID = "id"; @BeforeEach void configureMocks() { @@ -105,4 +108,63 @@ void givenBaseValueJWSAndFuzzParameterPresentInPayload_whenPayloadProcessed_then assertThat(result.action()).isEqualTo(USE_PAYLOAD); assertThat(result.processedPayload().toString()).isEqualTo("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImVtYW5vbiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"); } + + @Test + void givenBaseValueJWSAndFuzzParameterPresentInPayload_whenSigningKeyLoadedButResignOff_thenPayloadModifiedButNotResigned() { + String baseValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.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(RS512) + .build(); + + JWSPayloadProcessor processor = new JWSPayloadProcessor(intruderConfig, LOGGING, keysModel); + PayloadProcessingResult result = processor.processPayload(payloadData); + + assertThat(result.action()).isEqualTo(USE_PAYLOAD); + assertThat(result.processedPayload().toString()).isEqualTo("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImVtYW5vbiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"); + } + + @Test + void givenBaseValueJWSAndFuzzParameterPresentInPayload_whenResignOnButUnknownSigningKeyConfigured_thenPayloadModifiedButNotResigned() { + String baseValue = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.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("rogue") + .withSigningAlgorithm(RS512) + .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("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImVtYW5vbiIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"); + } + + @Test + void givenBaseValueJWSAndFuzzParameterPresentInPayload_whenResignOnAndSigningKeyPresentAndAlgorithmUnchanged_thenPayloadModifiedAndResignedButAlgUnchanged() { + String baseValue = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.LX5A6Hu00jlQ2n8s1SoVL4BEPjMiF1zrEs3qRtV08sbmsqxXV8bc8LarGm8YZj2OuXWL7aOkdBc9ezOBi5bjxsrtiUmwo5VWlU5Y6PXqGwH5v7w0kpRckdd0IA3nbrR2SyLQ1L1pQJk2PzoCvEpspBPMxtIyrK5MTep3Yx1Xn3aiw3aE1cHzOwK0xBIg-RW5qK5PwPa4H8T7eOOSMytS6N4AiZbeiIVHBWxmjrdp8AuC_fmfM1TQA_O8gK_1QkK3jPWkmbbtb48ut6dxz3H_gvPkPzsRE96nQ1qcOlbJjN0URcR2Tc1ACwZO4VpY4gujo_LwTsLiKQcmq0glFA3SIw"; + 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(RS512) + .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("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImVtYW5vbiIsImlhdCI6MTUxNjIzOTAyMn0.poPOxqjqp-CnC2b7eaf2QvfvAfawzp6k-P1QECIHN7KCTnFIlQbiJC4ZtLPH_0-o3HQcUGZbib3m1CVWeY21FIUTVUmOyjU8XuBohtBXRlXoaKXVWibrm5YiLC3yNQz5uAF-gdBB8ybvsmetK7JIZ8UvQdJ3mdvlAAW-3xFv8fs"); + } } \ No newline at end of file diff --git a/src/test/java/com/blackberry/jwteditor/KeysModelBuilder.java b/src/test/java/com/blackberry/jwteditor/KeysModelBuilder.java index b017ac1..5f80128 100644 --- a/src/test/java/com/blackberry/jwteditor/KeysModelBuilder.java +++ b/src/test/java/com/blackberry/jwteditor/KeysModelBuilder.java @@ -30,17 +30,29 @@ public class KeysModelBuilder { private final KeysModel model = new KeysModel(); public KeysModelBuilder withECKey(String pem) { - model.addKey(loadECKey(pem, nextKeyId())); + return withECKey(pem, nextKeyId()); + } + + public KeysModelBuilder withECKey(String pem, String keyId) { + model.addKey(loadECKey(pem, keyId)); return this; } public KeysModelBuilder withRSAKey(String pem) { - model.addKey(loadRSAKey(pem, nextKeyId())); + return withRSAKey(pem, nextKeyId()); + } + + public KeysModelBuilder withRSAKey(String pem, String keyId) { + model.addKey(loadRSAKey(pem, keyId)); return this; } public KeysModelBuilder withOKPKey(String pem) { - model.addKey(loadOKPKey(pem, nextKeyId())); + return withOKPKey(pem, nextKeyId()); + } + + public KeysModelBuilder withOKPKey(String pem, String keyId) { + model.addKey(loadOKPKey(pem, keyId)); return this; }