diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..45cf751
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,11 @@
+# Changelog
+
+## [0.0.2] - 2024-01-05
+
+### Added
+- Unknown signed string tab.
+- Enabled signers setting added to the main tab
+- _Known keys_ brute force technic added to the Attack mode
+
+### Changed
+- Upgrade dependencies: org.json:json
\ No newline at end of file
diff --git a/README.md b/README.md
index 5fda024..f3cadf9 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Sessionless
-Sessionless is a Burp Suite extension for editing, signing, verifying, attacking signed tokens: [Django TimestampSigner](https://docs.djangoproject.com/en/5.0/topics/signing/#verifying-timestamped-values), [ItsDangerous Signer](https://itsdangerous.palletsprojects.com/en/2.1.x/signer/), [Express cookie-session middleware](https://expressjs.com/en/resources/middleware/cookie-session.html), [OAuth2 Proxy](https://github.com/oauth2-proxy/oauth2-proxy) and [Tornado’s signed cookies](https://www.tornadoweb.org/en/stable/guide/security.html).
+Sessionless is a Burp Suite extension for editing, signing, verifying, attacking signed tokens: [Django TimestampSigner](https://docs.djangoproject.com/en/5.0/topics/signing/#verifying-timestamped-values), [ItsDangerous Signer](https://itsdangerous.palletsprojects.com/en/2.1.x/signer/), [Express cookie-session middleware](https://expressjs.com/en/resources/middleware/cookie-session.html), [OAuth2 Proxy](https://github.com/oauth2-proxy/oauth2-proxy), [Tornado’s signed cookies](https://www.tornadoweb.org/en/stable/guide/security.html) and Unknown signed string.
It provides automatic detection and in-line editing of token within HTTP requests/responses and WebSocket messages, signing of tokens and automation of brute force attacks against signed tokens implementations.
@@ -25,6 +25,14 @@ The `Editor View` supports a number of signed tokens: Django, Dangerous, Flask,
The Dangerous tab can be used for both, `Flask` and `Django` tokens, which are selected depending on whether a Dangerous or Django token is detected.
+The Unknown tab can be used to brute force unknown signed strings. Guessing mode works only with _Balanced_ brute force attack. It supports different message derivation technics, including:
+
+* _None_ message will be used as is
+* _CONCAT_ separator byte will be removed from the message and that new value will be used to calculate signature
+* _Tornado_ separator byte will be added to the end of the message string
+
+
+
### Editable Fields
A JSON text editor is provided to edit each component that contain JSON content:
@@ -55,6 +63,7 @@ A hex editor is provided to all signed tokens, except Express signatures. __NOTE
The `Brute force` option implements three types of attacks against signed tokens Signatures:
+* _Known keys_ will use previously found secret keys only
* _Fast_ will use default hashing algorithm and key derivation
* _Balanced_ will use all known key derivation technics, except PBKDF2HMAC
* _Deep_ will use all key derivation technics, including PBKDF2HMAC
diff --git a/build.gradle b/build.gradle
index 44ec7c4..ae24793 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ plugins {
}
group = 'one.d4d'
-version = '0.0.1'
+version = '0.0.2'
description = 'token-signer'
repositories {
@@ -37,7 +37,7 @@ dependencies {
'com.nimbusds:nimbus-jose-jwt:9.21',
'org.exbin.deltahex:deltahex-swing:0.1.2',
'com.fifesoft:rsyntaxtextarea:3.3.3',
- 'org.json:json:20230227',
+ 'org.json:json:20231013',
'org.apache.commons:commons-lang3:3.12.0'
)
testImplementation(
diff --git a/gitimg/unknown_tab.png b/gitimg/unknown_tab.png
new file mode 100644
index 0000000..bfcf0e1
Binary files /dev/null and b/gitimg/unknown_tab.png differ
diff --git a/src/main/java/burp/SessionlessExtension.java b/src/main/java/burp/SessionlessExtension.java
index 9a11727..08587e4 100644
--- a/src/main/java/burp/SessionlessExtension.java
+++ b/src/main/java/burp/SessionlessExtension.java
@@ -6,11 +6,7 @@
import burp.api.montoya.proxy.Proxy;
import burp.api.montoya.ui.UserInterface;
import burp.api.montoya.utilities.ByteUtils;
-import burp.config.BurpConfig;
-import burp.config.BurpConfigPersistence;
-import burp.config.BurpKeysModelPersistence;
-import burp.config.KeysModel;
-import burp.proxy.ProxyConfig;
+import burp.config.*;
import burp.proxy.ProxyHttpMessageHandler;
import burp.proxy.ProxyWsMessageHandler;
import one.d4d.sessionless.forms.ExtensionTab;
@@ -43,6 +39,11 @@ public void initialize(MontoyaApi api) {
UserInterface userInterface = api.userInterface();
Window suiteWindow = userInterface.swingUtils().suiteFrame();
+ Proxy proxy = api.proxy();
+ ProxyConfig proxyConfig = burpConfig.proxyConfig();
+ SignerConfig signerConfig = burpConfig.signerConfig();
+ ByteUtils byteUtils = api.utilities().byteUtils();
+
boolean isProVersion = api.burpSuite().version().edition() == PROFESSIONAL;
RstaFactory rstaFactory = new RstaFactory(userInterface, api.logging());
@@ -64,6 +65,7 @@ public void initialize(MontoyaApi api) {
api.logging(),
api.userInterface(),
api.collaborator().defaultPayloadGenerator(),
+ signerConfig,
editorCreationContext.editorMode() != READ_ONLY,
isProVersion
)
@@ -76,20 +78,17 @@ public void initialize(MontoyaApi api) {
api.logging(),
api.userInterface(),
api.collaborator().defaultPayloadGenerator(),
+ signerConfig,
editorCreationContext.editorMode() != READ_ONLY,
isProVersion
)
);
- Proxy proxy = api.proxy();
- ProxyConfig proxyConfig = burpConfig.proxyConfig();
- ByteUtils byteUtils = api.utilities().byteUtils();
-
- ProxyHttpMessageHandler proxyHttpMessageHandler = new ProxyHttpMessageHandler(proxyConfig, byteUtils);
+ ProxyHttpMessageHandler proxyHttpMessageHandler = new ProxyHttpMessageHandler(proxyConfig, signerConfig, byteUtils);
proxy.registerRequestHandler(proxyHttpMessageHandler);
proxy.registerResponseHandler(proxyHttpMessageHandler);
- ProxyWsMessageHandler proxyWsMessageHandler = new ProxyWsMessageHandler(proxyConfig, byteUtils);
+ ProxyWsMessageHandler proxyWsMessageHandler = new ProxyWsMessageHandler(proxyConfig, signerConfig, byteUtils);
proxy.registerWebSocketCreationHandler(proxyWebSocketCreation ->
proxyWebSocketCreation.proxyWebSocket().registerProxyMessageHandler(proxyWsMessageHandler)
);
diff --git a/src/main/java/burp/config/BurpConfig.java b/src/main/java/burp/config/BurpConfig.java
index 6055e59..44ee2e7 100644
--- a/src/main/java/burp/config/BurpConfig.java
+++ b/src/main/java/burp/config/BurpConfig.java
@@ -1,13 +1,16 @@
package burp.config;
-import burp.proxy.ProxyConfig;
import com.google.gson.annotations.Expose;
public class BurpConfig {
private final @Expose ProxyConfig proxyConfig = new ProxyConfig();
+ private final @Expose SignerConfig signerConfig = new SignerConfig();
public ProxyConfig proxyConfig() {
return proxyConfig;
}
+ public SignerConfig signerConfig() {
+ return signerConfig;
+ }
}
diff --git a/src/main/java/burp/proxy/ProxyConfig.java b/src/main/java/burp/config/ProxyConfig.java
similarity index 95%
rename from src/main/java/burp/proxy/ProxyConfig.java
rename to src/main/java/burp/config/ProxyConfig.java
index 427a5c1..332d037 100644
--- a/src/main/java/burp/proxy/ProxyConfig.java
+++ b/src/main/java/burp/config/ProxyConfig.java
@@ -1,5 +1,6 @@
-package burp.proxy;
+package burp.config;
+import burp.proxy.HighlightColor;
import com.google.gson.annotations.Expose;
import one.d4d.sessionless.utils.Utils;
diff --git a/src/main/java/burp/config/SignerConfig.java b/src/main/java/burp/config/SignerConfig.java
new file mode 100644
index 0000000..671477e
--- /dev/null
+++ b/src/main/java/burp/config/SignerConfig.java
@@ -0,0 +1,64 @@
+package burp.config;
+
+import com.google.gson.annotations.Expose;
+
+public class SignerConfig {
+ @Expose
+ private boolean enableDangerous;
+ @Expose
+ private boolean enableExpress;
+ @Expose
+ private boolean enableOAuth;
+ @Expose
+ private boolean enableTornado;
+ @Expose
+ private boolean enableUnknown;
+
+ public SignerConfig() {
+ this.enableDangerous = true;
+ this.enableExpress = true;
+ this.enableOAuth = false;
+ this.enableTornado = true;
+ this.enableUnknown = false;
+ }
+
+ public boolean isEnableDangerous() {
+ return enableDangerous;
+ }
+
+ public void setEnableDangerous(boolean enableDangerous) {
+ this.enableDangerous = enableDangerous;
+ }
+
+ public boolean isEnableExpress() {
+ return enableExpress;
+ }
+
+ public void setEnableExpress(boolean enableExpress) {
+ this.enableExpress = enableExpress;
+ }
+
+ public boolean isEnableOAuth() {
+ return enableOAuth;
+ }
+
+ public void setEnableOAuth(boolean enableOAuth) {
+ this.enableOAuth = enableOAuth;
+ }
+
+ public boolean isEnableTornado() {
+ return enableTornado;
+ }
+
+ public void setEnableTornado(boolean enableTornado) {
+ this.enableTornado = enableTornado;
+ }
+
+ public boolean isEnableUnknown() {
+ return enableUnknown;
+ }
+
+ public void setEnableUnknown(boolean enableUnknown) {
+ this.enableUnknown = enableUnknown;
+ }
+}
diff --git a/src/main/java/burp/proxy/AnnotationsModifier.java b/src/main/java/burp/proxy/AnnotationsModifier.java
index e207ab5..09994a2 100644
--- a/src/main/java/burp/proxy/AnnotationsModifier.java
+++ b/src/main/java/burp/proxy/AnnotationsModifier.java
@@ -5,6 +5,8 @@
import burp.api.montoya.http.message.Cookie;
import burp.api.montoya.http.message.params.ParsedHttpParameter;
import burp.api.montoya.utilities.ByteUtils;
+import burp.config.ProxyConfig;
+import burp.config.SignerConfig;
import one.d4d.sessionless.itsdangerous.model.SignedTokenObjectFinder;
import java.util.List;
@@ -12,10 +14,12 @@
class AnnotationsModifier {
private final ByteUtils byteUtils;
private final ProxyConfig proxyConfig;
+ private final SignerConfig signerConfig;
- AnnotationsModifier(ProxyConfig proxyConfig, ByteUtils byteUtils) {
+ AnnotationsModifier(ProxyConfig proxyConfig, SignerConfig signerConfig, ByteUtils byteUtils) {
this.byteUtils = byteUtils;
this.proxyConfig = proxyConfig;
+ this.signerConfig = signerConfig;
}
void updateAnnotationsIfApplicable(Annotations annotations, ByteArray data, List cookies, List params) {
@@ -37,7 +41,7 @@ private void updateAnnotations(Annotations annotations, String messageString, Li
}
private Counts countExtractedSignedTokenObjects(String messageString, List cookies, List params) {
- int count = SignedTokenObjectFinder.extractSignedTokenObjects(messageString, cookies, params).size();
+ int count = SignedTokenObjectFinder.extractSignedTokenObjects(signerConfig, messageString, cookies, params).size();
return new Counts(proxyConfig, count);
}
diff --git a/src/main/java/burp/proxy/ProxyHttpMessageHandler.java b/src/main/java/burp/proxy/ProxyHttpMessageHandler.java
index df3d77f..1c369ec 100644
--- a/src/main/java/burp/proxy/ProxyHttpMessageHandler.java
+++ b/src/main/java/burp/proxy/ProxyHttpMessageHandler.java
@@ -2,12 +2,14 @@
import burp.api.montoya.proxy.http.*;
import burp.api.montoya.utilities.ByteUtils;
+import burp.config.ProxyConfig;
+import burp.config.SignerConfig;
public class ProxyHttpMessageHandler implements ProxyRequestHandler, ProxyResponseHandler {
private final AnnotationsModifier annotationsModifier;
- public ProxyHttpMessageHandler(ProxyConfig proxyConfig, ByteUtils byteUtils) {
- this.annotationsModifier = new AnnotationsModifier(proxyConfig, byteUtils);
+ public ProxyHttpMessageHandler(ProxyConfig proxyConfig, SignerConfig signerConfig, ByteUtils byteUtils) {
+ this.annotationsModifier = new AnnotationsModifier(proxyConfig, signerConfig, byteUtils);
}
@Override
diff --git a/src/main/java/burp/proxy/ProxyWsMessageHandler.java b/src/main/java/burp/proxy/ProxyWsMessageHandler.java
index b0440c4..0eca6c6 100644
--- a/src/main/java/burp/proxy/ProxyWsMessageHandler.java
+++ b/src/main/java/burp/proxy/ProxyWsMessageHandler.java
@@ -2,12 +2,14 @@
import burp.api.montoya.proxy.websocket.*;
import burp.api.montoya.utilities.ByteUtils;
+import burp.config.ProxyConfig;
+import burp.config.SignerConfig;
public class ProxyWsMessageHandler implements ProxyMessageHandler {
private final AnnotationsModifier annotationsModifier;
- public ProxyWsMessageHandler(ProxyConfig proxyConfig, ByteUtils byteUtils) {
- this.annotationsModifier = new AnnotationsModifier(proxyConfig, byteUtils);
+ public ProxyWsMessageHandler(ProxyConfig proxyConfig, SignerConfig signerConfig, ByteUtils byteUtils) {
+ this.annotationsModifier = new AnnotationsModifier(proxyConfig, signerConfig, byteUtils);
}
@Override
diff --git a/src/main/java/one/d4d/sessionless/forms/EditorTab.form b/src/main/java/one/d4d/sessionless/forms/EditorTab.form
index 60c0fcb..4fce046 100644
--- a/src/main/java/one/d4d/sessionless/forms/EditorTab.form
+++ b/src/main/java/one/d4d/sessionless/forms/EditorTab.form
@@ -529,6 +529,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/one/d4d/sessionless/forms/EditorTab.java b/src/main/java/one/d4d/sessionless/forms/EditorTab.java
index 656ce56..e578ab6 100644
--- a/src/main/java/one/d4d/sessionless/forms/EditorTab.java
+++ b/src/main/java/one/d4d/sessionless/forms/EditorTab.java
@@ -3,6 +3,7 @@
import burp.api.montoya.collaborator.CollaboratorPayloadGenerator;
import burp.api.montoya.ui.Selection;
import burp.api.montoya.ui.editor.extension.ExtensionProvidedEditor;
+import burp.config.SignerConfig;
import one.d4d.sessionless.hexcodearea.HexCodeAreaFactory;
import one.d4d.sessionless.presenter.EditorPresenter;
import one.d4d.sessionless.presenter.PresenterStore;
@@ -32,12 +33,14 @@ public abstract class EditorTab implements ExtensionProvidedEditor {
public static final int TAB_EXPRESS = 1;
public static final int TAB_OAUTH = 2;
public static final int TAB_TORNADO = 3;
+ public static final int TAB_UNKNOWN = 4;
private static final int MAX_JOSE_OBJECT_STRING_LENGTH = 68;
final EditorPresenter presenter;
private final RstaFactory rstaFactory;
private final boolean editable;
private final HexCodeAreaFactory hexCodeAreaFactory;
private final boolean isProVersion;
+ private final SignerConfig signerConfig;
private int mode;
private JPanel mainPanel;
private JTabbedPane tabbedPane;
@@ -65,10 +68,14 @@ public abstract class EditorTab implements ExtensionProvidedEditor {
private JCheckBox checkBoxDjango;
private JCheckBox checkBoxCompress;
private JButton buttonAttack;
+ private RSyntaxTextArea textAreaUnknownStringMessage;
+ private JPanel panelUnknownStringSeparator;
+ private RSyntaxTextArea textAreaUnknownStringSignature;
private CodeArea codeAreaDangerousSignature;
private CodeArea codeAreaDangerousSeparator;
private CodeArea codeAreaOAuthSignature;
private CodeArea codeAreaTornadoSignature;
+ private CodeArea codeAreaUnknownSeparator;
EditorTab(
PresenterStore presenters,
@@ -76,17 +83,20 @@ public abstract class EditorTab implements ExtensionProvidedEditor {
HexCodeAreaFactory hexAreaCodeFactory,
CollaboratorPayloadGenerator collaboratorPayloadGenerator,
ErrorLoggingActionListenerFactory actionListenerFactory,
+ SignerConfig signerConfig,
boolean editable,
boolean isProVersion) {
this.rstaFactory = rstaFactory;
this.editable = editable;
this.hexCodeAreaFactory = hexAreaCodeFactory;
this.isProVersion = isProVersion;
+ this.signerConfig = signerConfig;
this.presenter = new EditorPresenter(
this,
collaboratorPayloadGenerator,
actionListenerFactory,
- presenters);
+ presenters,
+ signerConfig);
DocumentListener documentListener = new DocumentListener() {
@Override
@@ -116,6 +126,8 @@ public void changedUpdate(DocumentEvent e) {
textAreaTornadoTimestamp.getDocument().addDocumentListener(documentListener);
textAreaTornadoName.getDocument().addDocumentListener(documentListener);
textAreaTornadoValue.getDocument().addDocumentListener(documentListener);
+ textAreaUnknownStringMessage.getDocument().addDocumentListener(documentListener);
+ textAreaUnknownStringSignature.getDocument().addDocumentListener(documentListener);
checkBoxIsJSON.addActionListener(e -> presenter.componentChanged());
checkBoxDjango.addActionListener(e -> presenter.componentChanged());
@@ -125,6 +137,7 @@ public void changedUpdate(DocumentEvent e) {
codeAreaDangerousSeparator.addDataChangedListener(presenter::componentChanged);
codeAreaOAuthSignature.addDataChangedListener(presenter::componentChanged);
codeAreaTornadoSignature.addDataChangedListener(presenter::componentChanged);
+ codeAreaUnknownSeparator.addDataChangedListener(presenter::componentChanged);
comboBoxSignedToken.addActionListener(e -> presenter.onSelectionChanged());
@@ -294,6 +307,27 @@ public boolean getDangerouseIsCompressed() {
public void setDangerouseIsCompressed(boolean enabled) {
checkBoxCompress.setSelected(enabled);
}
+ public String getUnknownMessage() {
+ return textAreaUnknownStringMessage.getText();
+ }
+
+ public void setUnknownMessage(String text) {
+ textAreaUnknownStringMessage.setText(text);
+ }
+ public String getUnknownSignature() {
+ return textAreaUnknownStringSignature.getText();
+ }
+
+ public void setUnknownSignature(String signature) {
+ textAreaUnknownStringSignature.setText(signature);
+ }
+ public byte[] getUnknownSeparator() {
+ return Utils.getCodeAreaData(codeAreaUnknownSeparator);
+ }
+
+ public void setUnknownSeparator(byte[] separator) {
+ codeAreaUnknownSeparator.setData(new ByteArrayEditableData(separator));
+ }
public void setSignedTokenObjects(List signedTokenObjectStrings) {
comboBoxSignedToken.setModel(new MaxLengthStringComboBoxModel(MAX_JOSE_OBJECT_STRING_LENGTH, signedTokenObjectStrings));
@@ -321,20 +355,26 @@ private void createUIComponents() {
codeAreaTornadoSignature = hexCodeAreaFactory.build();
panelTornadoSignature.add(codeAreaTornadoSignature);
+ panelUnknownStringSeparator = new JPanel(new BorderLayout());
+ codeAreaUnknownSeparator = hexCodeAreaFactory.build();
+ panelUnknownStringSeparator.add(codeAreaUnknownSeparator);
+
// Create the Attack popup menu
JPopupMenu popupMenuAttack = new JPopupMenu();
+ JMenuItem menuItemAttackBruteForceKnownKeys = new JMenuItem(Utils.getResourceString("editor_view_button_attack_known_keys"));
JMenuItem menuItemAttackBruteForce = new JMenuItem(Utils.getResourceString("editor_view_button_attack_fast"));
JMenuItem menuItemAttackBruteForceBalanced = new JMenuItem(Utils.getResourceString("editor_view_button_attack_balanced"));
JMenuItem menuItemAttackBruteForceDeep = new JMenuItem(Utils.getResourceString("editor_view_button_attack_deep"));
// Attach the event handlers to the popup menu click events
-
+ menuItemAttackBruteForceKnownKeys.addActionListener(e -> presenter.onAttackKnownKeysClicked());
menuItemAttackBruteForce.addActionListener(e -> presenter.onAttackFastClicked());
menuItemAttackBruteForceBalanced.addActionListener(e -> presenter.onAttackBalancedClicked());
menuItemAttackBruteForceDeep.addActionListener(e -> presenter.onAttackDeepClicked());
// Add the buttons to the popup menu
+ popupMenuAttack.add(menuItemAttackBruteForceKnownKeys);
popupMenuAttack.add(menuItemAttackBruteForce);
popupMenuAttack.add(menuItemAttackBruteForceBalanced);
popupMenuAttack.add(menuItemAttackBruteForceDeep);
@@ -358,6 +398,8 @@ private void createUIComponents() {
textAreaTornadoTimestamp = rstaFactory.buildDefaultTextArea();
textAreaTornadoName = rstaFactory.buildDefaultTextArea();
textAreaTornadoValue = rstaFactory.buildDefaultTextArea();
+ textAreaUnknownStringMessage = rstaFactory.buildDefaultTextArea();
+ textAreaUnknownStringSignature = rstaFactory.buildDefaultTextArea();
}
private void onBruteForceAttackClicked() {
@@ -437,7 +479,18 @@ public void setTornadoMode() {
EditationAllowed editationAllowed = editable ? ALLOWED : READ_ONLY;
codeAreaTornadoSignature.setEditationAllowed(editationAllowed);
}
+ public void setUnknownMode() {
+ mode = TAB_UNKNOWN;
+ enableTabAtIndex(TAB_UNKNOWN);
+ buttonBruteForceAttack.setEnabled(editable);
+ buttonAttack.setEnabled(editable);
+
+ textAreaUnknownStringMessage.setEditable(editable);
+ textAreaUnknownStringSignature.setEditable(editable);
+ EditationAllowed editationAllowed = editable ? ALLOWED : READ_ONLY;
+ codeAreaUnknownSeparator.setEditationAllowed(editationAllowed);
+ }
@Override
public String caption() {
diff --git a/src/main/java/one/d4d/sessionless/forms/KeysTableColumns.java b/src/main/java/one/d4d/sessionless/forms/KeysTableColumns.java
index 90928e5..25448fd 100644
--- a/src/main/java/one/d4d/sessionless/forms/KeysTableColumns.java
+++ b/src/main/java/one/d4d/sessionless/forms/KeysTableColumns.java
@@ -6,9 +6,10 @@
enum KeysTableColumns {
ID("table_id", 30, String.class),
- SECRET("table_secret", 40, String.class),
+ SECRET("table_secret", 30, String.class),
ALGORITHM("table_algorithm", 10, String.class),
DERIVATION("table_derivation",10, String.class),
+ MESSAGE_DERIVATION("table_message_derivation", 10, String.class),
DIGEST("table_digest",10, String.class);
private final String label;
diff --git a/src/main/java/one/d4d/sessionless/forms/KeysTableModel.java b/src/main/java/one/d4d/sessionless/forms/KeysTableModel.java
index caf50b0..eb6c0b9 100644
--- a/src/main/java/one/d4d/sessionless/forms/KeysTableModel.java
+++ b/src/main/java/one/d4d/sessionless/forms/KeysTableModel.java
@@ -49,6 +49,7 @@ public Object getValueAt(int rowIndex, int columnIndex) {
case SECRET -> key.getSecret();
case ALGORITHM -> key.getDigestMethod();
case DERIVATION -> key.getKeyDerivation();
+ case MESSAGE_DERIVATION -> key.getMessageDerivation();
case DIGEST -> key.getMessageDigestAlgorythm();
};
}
diff --git a/src/main/java/one/d4d/sessionless/forms/RequestEditorView.java b/src/main/java/one/d4d/sessionless/forms/RequestEditorView.java
index 9d7e716..5f7d8a2 100644
--- a/src/main/java/one/d4d/sessionless/forms/RequestEditorView.java
+++ b/src/main/java/one/d4d/sessionless/forms/RequestEditorView.java
@@ -7,6 +7,7 @@
import burp.api.montoya.logging.Logging;
import burp.api.montoya.ui.UserInterface;
import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpRequestEditor;
+import burp.config.SignerConfig;
import one.d4d.sessionless.hexcodearea.HexCodeAreaFactory;
import one.d4d.sessionless.presenter.PresenterStore;
import one.d4d.sessionless.rsta.RstaFactory;
@@ -25,6 +26,7 @@ public RequestEditorView(
Logging logging,
UserInterface userInterface,
CollaboratorPayloadGenerator collaboratorPayloadGenerator,
+ SignerConfig signerConfig,
boolean editable,
boolean isProVersion) {
super(
@@ -33,6 +35,7 @@ public RequestEditorView(
new HexCodeAreaFactory(logging, userInterface),
collaboratorPayloadGenerator,
new ErrorLoggingActionListenerFactory(logging),
+ signerConfig,
editable,
isProVersion
);
diff --git a/src/main/java/one/d4d/sessionless/forms/ResponseEditorView.java b/src/main/java/one/d4d/sessionless/forms/ResponseEditorView.java
index 0db26e8..0ce6cd1 100644
--- a/src/main/java/one/d4d/sessionless/forms/ResponseEditorView.java
+++ b/src/main/java/one/d4d/sessionless/forms/ResponseEditorView.java
@@ -7,6 +7,7 @@
import burp.api.montoya.logging.Logging;
import burp.api.montoya.ui.UserInterface;
import burp.api.montoya.ui.editor.extension.ExtensionProvidedHttpResponseEditor;
+import burp.config.SignerConfig;
import one.d4d.sessionless.hexcodearea.HexCodeAreaFactory;
import one.d4d.sessionless.presenter.PresenterStore;
import one.d4d.sessionless.rsta.RstaFactory;
@@ -24,6 +25,7 @@ public ResponseEditorView(
Logging logging,
UserInterface userInterface,
CollaboratorPayloadGenerator collaboratorPayloadGenerator,
+ SignerConfig signerConfig,
boolean editable,
boolean isProVersion) {
super(
@@ -32,6 +34,7 @@ public ResponseEditorView(
new HexCodeAreaFactory(logging, userInterface),
collaboratorPayloadGenerator,
new ErrorLoggingActionListenerFactory(logging),
+ signerConfig,
editable,
isProVersion
);
diff --git a/src/main/java/one/d4d/sessionless/forms/SettingsView.form b/src/main/java/one/d4d/sessionless/forms/SettingsView.form
index f924d97..5ace786 100644
--- a/src/main/java/one/d4d/sessionless/forms/SettingsView.form
+++ b/src/main/java/one/d4d/sessionless/forms/SettingsView.form
@@ -1,9 +1,9 @@
diff --git a/src/main/java/one/d4d/sessionless/forms/SettingsView.java b/src/main/java/one/d4d/sessionless/forms/SettingsView.java
index b7dc267..4c5e754 100644
--- a/src/main/java/one/d4d/sessionless/forms/SettingsView.java
+++ b/src/main/java/one/d4d/sessionless/forms/SettingsView.java
@@ -2,8 +2,9 @@
import burp.api.montoya.ui.UserInterface;
import burp.config.BurpConfig;
+import burp.config.SignerConfig;
import burp.proxy.HighlightColor;
-import burp.proxy.ProxyConfig;
+import burp.config.ProxyConfig;
import javax.swing.*;
import java.awt.*;
@@ -19,10 +20,18 @@ public class SettingsView {
private JComboBox comboBoxHighlightColor;
private JLabel labelHighlightToken;
private JLabel labelHighlightColor;
+ private JPanel signerPanel;
+ private JLabel signerLabel;
+ private JCheckBox checkBoxEnableUnknownSignedString;
+ private JCheckBox checkBoxEnableDangerousSignedString;
+ private JCheckBox checkBoxEnableExpressSignedString;
+ private JCheckBox checkBoxEnableOAuthSignedString;
+ private JCheckBox checkBoxEnableTornadoSignedString;
public SettingsView(Window parent, BurpConfig burpConfig, UserInterface userInterface) {
this.parent = parent;
ProxyConfig proxyConfig = burpConfig.proxyConfig();
+ SignerConfig signerConfig = burpConfig.signerConfig();
checkBoxHighlightToken.setSelected(proxyConfig.highlightToken());
checkBoxHighlightToken.addActionListener(e -> {
@@ -35,10 +44,34 @@ public SettingsView(Window parent, BurpConfig burpConfig, UserInterface userInte
comboBoxHighlightColor.setEnabled(proxyConfig.highlightToken());
comboBoxHighlightColor.addActionListener(e -> proxyConfig.setHighlightColor((HighlightColor) comboBoxHighlightColor.getSelectedItem()));
-
proxyLabel.setFont(proxyLabel.getFont().deriveFont(BOLD));
userInterface.applyThemeToComponent(mainPanel);
comboBoxHighlightColor.setRenderer(new HighlightComboRenderer());
+
+ checkBoxEnableDangerousSignedString.setSelected(signerConfig.isEnableDangerous());
+ checkBoxEnableDangerousSignedString.addActionListener(e -> {
+ signerConfig.setEnableDangerous(checkBoxEnableDangerousSignedString.isSelected());
+ });
+
+ checkBoxEnableExpressSignedString.setSelected(signerConfig.isEnableExpress());
+ checkBoxEnableExpressSignedString.addActionListener(e -> {
+ signerConfig.setEnableExpress(checkBoxEnableExpressSignedString.isSelected());
+ });
+
+ checkBoxEnableOAuthSignedString.setSelected(signerConfig.isEnableOAuth());
+ checkBoxEnableOAuthSignedString.addActionListener(e -> {
+ signerConfig.setEnableOAuth(checkBoxEnableOAuthSignedString.isSelected());
+ });
+
+ checkBoxEnableTornadoSignedString.setSelected(signerConfig.isEnableTornado());
+ checkBoxEnableTornadoSignedString.addActionListener(e -> {
+ signerConfig.setEnableTornado(checkBoxEnableTornadoSignedString.isSelected());
+ });
+
+ checkBoxEnableUnknownSignedString.setSelected(signerConfig.isEnableUnknown());
+ checkBoxEnableUnknownSignedString.addActionListener(e -> {
+ signerConfig.setEnableUnknown(checkBoxEnableUnknownSignedString.isSelected());
+ });
}
private static class HighlightComboRenderer implements ListCellRenderer {
diff --git a/src/main/java/one/d4d/sessionless/forms/dialog/AttackDialog.java b/src/main/java/one/d4d/sessionless/forms/dialog/AttackDialog.java
index 2492dca..4623fa9 100644
--- a/src/main/java/one/d4d/sessionless/forms/dialog/AttackDialog.java
+++ b/src/main/java/one/d4d/sessionless/forms/dialog/AttackDialog.java
@@ -118,6 +118,8 @@ private void onOK() {
s = new OauthProxyTokenSigner(selectedKey);
} else if (tokenObject instanceof TornadoSignedToken) {
s = new TornadoTokenSigner(selectedKey);
+ } else if (tokenObject instanceof UnknownSignedToken) {
+ s = new TokenSigner(selectedKey);
} else {
throw new Exception("Unknown");
}
diff --git a/src/main/java/one/d4d/sessionless/forms/dialog/BruteForceAttackDialog.java b/src/main/java/one/d4d/sessionless/forms/dialog/BruteForceAttackDialog.java
index 92f9ce2..b912940 100644
--- a/src/main/java/one/d4d/sessionless/forms/dialog/BruteForceAttackDialog.java
+++ b/src/main/java/one/d4d/sessionless/forms/dialog/BruteForceAttackDialog.java
@@ -25,6 +25,7 @@ public BruteForceAttackDialog(
ErrorLoggingActionListenerFactory actionListenerFactory,
List signingSecrets,
List signingSalts,
+ List signingKeys,
Attack mode,
SignedToken token
) {
@@ -56,16 +57,17 @@ public void actionPerformed(ActionEvent e) {
}, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
// Logic
- lblStatus.setText(String.format(
+ String lblText = String.format(
Utils.getResourceString("attack_dialog_progress_bar_status"),
- signingSecrets.size(),
- signingSalts.size(),
+ mode == Attack.KNOWN ? signingKeys.size() : signingSecrets.size(),
+ mode == Attack.KNOWN ? signingKeys.size() : signingSalts.size(),
mode.getName()
- ));
+ );
+ lblStatus.setText(lblText);
SwingWorker sw = new SwingWorker() {
@Override
protected Void doInBackground() throws Exception {
- BruteForce bf = new BruteForce(signingSecrets, signingSalts, mode, token);
+ BruteForce bf = new BruteForce(signingSecrets, signingSalts, signingKeys, mode, token);
SecretKey k = bf.search();
if (k != null) {
secretKey = k;
diff --git a/src/main/java/one/d4d/sessionless/forms/dialog/NewKeyDialog.form b/src/main/java/one/d4d/sessionless/forms/dialog/NewKeyDialog.form
index 162d48b..23c501f 100644
--- a/src/main/java/one/d4d/sessionless/forms/dialog/NewKeyDialog.form
+++ b/src/main/java/one/d4d/sessionless/forms/dialog/NewKeyDialog.form
@@ -3,7 +3,7 @@
-
+
@@ -67,7 +67,7 @@
-
+
@@ -88,7 +88,7 @@
-
+
@@ -112,7 +112,7 @@
-
+
@@ -126,7 +126,7 @@
-
+
@@ -136,7 +136,7 @@
-
+
@@ -147,6 +147,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/one/d4d/sessionless/forms/dialog/NewKeyDialog.java b/src/main/java/one/d4d/sessionless/forms/dialog/NewKeyDialog.java
index 9e6c97e..a425932 100644
--- a/src/main/java/one/d4d/sessionless/forms/dialog/NewKeyDialog.java
+++ b/src/main/java/one/d4d/sessionless/forms/dialog/NewKeyDialog.java
@@ -2,6 +2,7 @@
import one.d4d.sessionless.itsdangerous.Algorithms;
import one.d4d.sessionless.itsdangerous.Derivation;
+import one.d4d.sessionless.itsdangerous.MessageDerivation;
import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
import one.d4d.sessionless.keys.Key;
import one.d4d.sessionless.keys.SecretKey;
@@ -29,6 +30,7 @@ public class NewKeyDialog extends KeyDialog {
private JTextField textFieldKeyID;
private JCheckBox checkBoxSecretJSON;
private JCheckBox checkBoxSaltJSON;
+ private JComboBox comboBoxMessageDerivation;
private SecretKey key;
@@ -43,6 +45,7 @@ public NewKeyDialog(Window parent, PresenterStore presenters) {
"",
Algorithms.SHA1,
Derivation.HMAC,
+ MessageDerivation.NONE,
MessageDigestAlgorithm.SHA1);
originalId = null;
}
@@ -58,6 +61,7 @@ public NewKeyDialog(Window parent, PresenterStore presenters, SecretKey key) {
key.getSeparator(),
key.getDigestMethod(),
key.getKeyDerivation(),
+ key.getMessageDerivation(),
key.getMessageDigestAlgorythm()
);
}
@@ -72,6 +76,7 @@ private NewKeyDialog(
String separator,
Algorithms algorithms,
Derivation derivation,
+ MessageDerivation messageDerivation,
MessageDigestAlgorithm digest) {
super(parent, TITLE_RESOURCE_ID);
this.presenters = presenters;
@@ -109,6 +114,8 @@ private NewKeyDialog(
comboBoxDigest.setSelectedItem(digest);
comboBoxDerivation.setModel(new DefaultComboBoxModel<>(Derivation.values()));
comboBoxDerivation.setSelectedItem(derivation);
+ comboBoxMessageDerivation.setModel(new DefaultComboBoxModel<>(MessageDerivation.values()));
+ comboBoxMessageDerivation.setSelectedItem(messageDerivation);
}
private void checkInput() {
@@ -133,6 +140,7 @@ void onOK() {
textFieldSeparator.getText(),
(Algorithms) comboBoxAlgorythm.getSelectedItem(),
(Derivation) comboBoxDerivation.getSelectedItem(),
+ (MessageDerivation) comboBoxMessageDerivation.getSelectedItem(),
(MessageDigestAlgorithm) comboBoxDigest.getSelectedItem()
);
super.onOK();
diff --git a/src/main/java/one/d4d/sessionless/forms/dialog/SignDialog.java b/src/main/java/one/d4d/sessionless/forms/dialog/SignDialog.java
index 36e277f..9d23cf8 100644
--- a/src/main/java/one/d4d/sessionless/forms/dialog/SignDialog.java
+++ b/src/main/java/one/d4d/sessionless/forms/dialog/SignDialog.java
@@ -60,6 +60,8 @@ private void onOK() {
s = new OauthProxyTokenSigner(selectedKey);
} else if (tokenObject instanceof TornadoSignedToken) {
s = new TornadoTokenSigner(selectedKey);
+ } else if (tokenObject instanceof UnknownSignedToken) {
+ s = new TokenSigner(selectedKey);
} else {
throw new Exception("Unknown");
}
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/Attack.java b/src/main/java/one/d4d/sessionless/itsdangerous/Attack.java
index 4b0ebf2..082a86f 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/Attack.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/Attack.java
@@ -3,6 +3,8 @@
import com.google.gson.annotations.SerializedName;
public enum Attack {
+ @SerializedName("Known")
+ KNOWN("Known"),
@SerializedName("Fast")
FAST("Fast"),
@SerializedName("Balanced")
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/BruteForce.java b/src/main/java/one/d4d/sessionless/itsdangerous/BruteForce.java
index 3dfb558..c977e5b 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/BruteForce.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/BruteForce.java
@@ -2,6 +2,7 @@
import one.d4d.sessionless.itsdangerous.crypto.TokenSigner;
import one.d4d.sessionless.itsdangerous.model.SignedToken;
+import one.d4d.sessionless.itsdangerous.model.UnknownSignedToken;
import one.d4d.sessionless.keys.SecretKey;
import java.util.ArrayList;
@@ -10,12 +11,14 @@
public class BruteForce {
private final List secrets;
private final List salts;
+ private final List signingKeys;
private final Attack scanConfiguration;
private final SignedToken token;
- public BruteForce(List secrets, List salts, Attack scanConfiguration, SignedToken token) {
+ public BruteForce(List secrets, List salts, List signingKeys, Attack scanConfiguration, SignedToken token) {
this.secrets = secrets;
this.salts = salts;
+ this.signingKeys = signingKeys;
this.scanConfiguration = scanConfiguration;
this.token = token;
}
@@ -23,6 +26,13 @@ public BruteForce(List secrets, List salts, Attack scanConfigura
public List prepare() {
List attacks = new ArrayList<>();
TokenSigner is = token.getSigner();
+ if (scanConfiguration == Attack.KNOWN) {
+ this.signingKeys.forEach(key -> {
+ TokenSigner ks = new TokenSigner(key);
+ attacks.add(ks);
+ });
+ return attacks;
+ }
for (String secret : secrets) {
if (scanConfiguration == Attack.FAST) {
if (is.getKeyDerivation() == Derivation.NONE) {
@@ -38,31 +48,37 @@ public List prepare() {
}
}
} else {
- for (Derivation d : Derivation.values()) {
- if (d == Derivation.NONE) {
- TokenSigner s = is.clone();
- s.setKeyDerivation(d);
- s.setSecretKey(secret.getBytes());
- attacks.add(s);
- } else if (d == Derivation.HASH ) {
- for (MessageDigestAlgorithm m : MessageDigestAlgorithm.values()) {
+ for (MessageDerivation md : MessageDerivation.values()) {
+ if(md != MessageDerivation.NONE && !(token instanceof UnknownSignedToken)) continue;
+ for (Derivation d : Derivation.values()) {
+ if (d == Derivation.NONE) {
TokenSigner s = is.clone();
s.setKeyDerivation(d);
+ s.setMessageDerivation(md);
s.setSecretKey(secret.getBytes());
- s.setMessageDigestAlgorithm(m);
attacks.add(s);
- }
- } else {
- if (d == Derivation.PBKDF2HMAC && scanConfiguration != Attack.Deep) continue;
- for (MessageDigestAlgorithm m : MessageDigestAlgorithm.values()) {
- for (String salt : salts) {
+ } else if (d == Derivation.HASH) {
+ for (MessageDigestAlgorithm m : MessageDigestAlgorithm.values()) {
TokenSigner s = is.clone();
s.setKeyDerivation(d);
+ s.setMessageDerivation(md);
s.setSecretKey(secret.getBytes());
- s.setSalt(salt.getBytes());
s.setMessageDigestAlgorithm(m);
attacks.add(s);
}
+ } else {
+ if (d == Derivation.PBKDF2HMAC && scanConfiguration != Attack.Deep) continue;
+ for (MessageDigestAlgorithm m : MessageDigestAlgorithm.values()) {
+ for (String salt : salts) {
+ TokenSigner s = is.clone();
+ s.setKeyDerivation(d);
+ s.setMessageDerivation(md);
+ s.setSecretKey(secret.getBytes());
+ s.setSalt(salt.getBytes());
+ s.setMessageDigestAlgorithm(m);
+ attacks.add(s);
+ }
+ }
}
}
}
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/MessageDerivation.java b/src/main/java/one/d4d/sessionless/itsdangerous/MessageDerivation.java
new file mode 100644
index 0000000..8298ba0
--- /dev/null
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/MessageDerivation.java
@@ -0,0 +1,14 @@
+package one.d4d.sessionless.itsdangerous;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+
+public enum MessageDerivation {
+ @Expose @SerializedName("0") NONE("none"),
+ @Expose @SerializedName("1") CONCAT("concat"),
+ @Expose @SerializedName("2") TORNADO("tornado");
+ public final String name;
+ MessageDerivation(String name) {
+ this.name = name;
+ }
+}
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/DangerousTokenSigner.java b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/DangerousTokenSigner.java
index 20df519..febc3ea 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/DangerousTokenSigner.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/DangerousTokenSigner.java
@@ -1,10 +1,7 @@
package one.d4d.sessionless.itsdangerous.crypto;
import com.google.common.primitives.Bytes;
-import one.d4d.sessionless.itsdangerous.Algorithms;
-import one.d4d.sessionless.itsdangerous.BadSignatureException;
-import one.d4d.sessionless.itsdangerous.Derivation;
-import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
+import one.d4d.sessionless.itsdangerous.*;
import one.d4d.sessionless.keys.SecretKey;
import one.d4d.sessionless.utils.Utils;
@@ -31,11 +28,12 @@ public DangerousTokenSigner(Algorithms digestMethod, Derivation keyDerivation, b
public DangerousTokenSigner(
Algorithms algorithm,
Derivation keyDerivation,
+ MessageDerivation messageDerivation,
MessageDigestAlgorithm digest,
byte[] secret_key,
byte[] salt,
byte sep) {
- super(algorithm, keyDerivation, digest, secret_key, salt, sep);
+ super(algorithm, keyDerivation, messageDerivation, digest, secret_key, salt, sep);
}
public DangerousTokenSigner(String digestMethod, String keyDerivation, byte[] secret_key, byte[] salt, byte sep) {
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/DjangoTokenSigner.java b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/DjangoTokenSigner.java
index a5c0117..e520892 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/DjangoTokenSigner.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/DjangoTokenSigner.java
@@ -2,6 +2,7 @@
import one.d4d.sessionless.itsdangerous.Algorithms;
import one.d4d.sessionless.itsdangerous.Derivation;
+import one.d4d.sessionless.itsdangerous.MessageDerivation;
import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
import one.d4d.sessionless.keys.SecretKey;
@@ -29,10 +30,11 @@ public DjangoTokenSigner(String digestMethod, String keyDerivation, byte[] secre
public DjangoTokenSigner(
Algorithms algorithm,
Derivation keyDerivation,
+ MessageDerivation messageDerivation,
MessageDigestAlgorithm digest,
byte[] secret_key,
byte[] salt,
byte sep) {
- super(algorithm, keyDerivation, digest, secret_key, salt, sep);
+ super(algorithm, keyDerivation, messageDerivation, digest, secret_key, salt, sep);
}
}
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/ExpressTokenSigner.java b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/ExpressTokenSigner.java
index 04f82f6..9856308 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/ExpressTokenSigner.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/ExpressTokenSigner.java
@@ -13,7 +13,7 @@ public ExpressTokenSigner(SecretKey key) {
}
public ExpressTokenSigner() {
- super(Algorithms.SHA1, Derivation.NONE, MessageDigestAlgorithm.NONE, new byte[]{}, new byte[]{}, (byte) 0);
+ super(Algorithms.SHA1, Derivation.NONE, MessageDerivation.NONE, MessageDigestAlgorithm.NONE, new byte[]{}, new byte[]{}, (byte) 0);
}
public ExpressTokenSigner(byte sep) {
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/JSONWebSignatureTokenSigner.java b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/JSONWebSignatureTokenSigner.java
index 91b08d1..c0c907f 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/JSONWebSignatureTokenSigner.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/JSONWebSignatureTokenSigner.java
@@ -2,6 +2,7 @@
import one.d4d.sessionless.itsdangerous.Algorithms;
import one.d4d.sessionless.itsdangerous.Derivation;
+import one.d4d.sessionless.itsdangerous.MessageDerivation;
import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
import one.d4d.sessionless.keys.SecretKey;
@@ -13,6 +14,6 @@ public JSONWebSignatureTokenSigner(SecretKey key) {
}
public JSONWebSignatureTokenSigner(byte sep) {
- super(Algorithms.SHA256, Derivation.NONE, MessageDigestAlgorithm.NONE, new byte[]{}, new byte[]{}, sep);
+ super(Algorithms.SHA256, Derivation.NONE, MessageDerivation.NONE, MessageDigestAlgorithm.NONE, new byte[]{}, new byte[]{}, sep);
}
}
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/OauthProxyTokenSigner.java b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/OauthProxyTokenSigner.java
index b6d76d3..fa53815 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/OauthProxyTokenSigner.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/OauthProxyTokenSigner.java
@@ -1,9 +1,6 @@
package one.d4d.sessionless.itsdangerous.crypto;
-import one.d4d.sessionless.itsdangerous.Algorithms;
-import one.d4d.sessionless.itsdangerous.Derivation;
-import one.d4d.sessionless.itsdangerous.DerivationException;
-import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
+import one.d4d.sessionless.itsdangerous.*;
import one.d4d.sessionless.utils.Utils;
import one.d4d.sessionless.keys.SecretKey;
import javax.crypto.Mac;
@@ -15,10 +12,10 @@ public OauthProxyTokenSigner(SecretKey key) {
super(key);
}
public OauthProxyTokenSigner() {
- super(Algorithms.SHA256, Derivation.NONE, MessageDigestAlgorithm.NONE, new byte[] {}, new byte[] {}, (byte)'|');
+ super(Algorithms.SHA256, Derivation.NONE, MessageDerivation.NONE, MessageDigestAlgorithm.NONE, new byte[] {}, new byte[] {}, (byte)'|');
}
public OauthProxyTokenSigner(Algorithms digestMethod, byte[] secret_key, byte sep) {
- super(digestMethod, Derivation.NONE, MessageDigestAlgorithm.NONE, secret_key, new byte[] {}, sep);
+ super(digestMethod, Derivation.NONE, MessageDerivation.NONE, MessageDigestAlgorithm.NONE, secret_key, new byte[] {}, sep);
}
@Override
public byte[] derive_key() throws DerivationException {
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/TokenSigner.java b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/TokenSigner.java
index 5c800a1..8d9d127 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/TokenSigner.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/TokenSigner.java
@@ -21,6 +21,7 @@
public class TokenSigner implements Cloneable {
public Algorithms digestMethod = Algorithms.SHA1;
public Derivation keyDerivation = Derivation.HMAC;
+ public MessageDerivation messageDerivation = MessageDerivation.NONE;
public MessageDigestAlgorithm messageDigestAlgorithm = MessageDigestAlgorithm.SHA1;
public byte[] secret_key;
public byte[] salt = "itsdangerous.Signer".getBytes();
@@ -40,6 +41,7 @@ public TokenSigner(byte[] secret_key, byte sep) {
public TokenSigner(SecretKey key) {
this.digestMethod = key.getDigestMethod();
this.keyDerivation = key.getKeyDerivation();
+ this.messageDerivation = key.getMessageDerivation();
this.secret_key = key.getSecret().getBytes();
this.salt = key.getSalt().getBytes();
this.sep = key.getSeparator().getBytes().length > 0 ? key.getSeparator().getBytes()[0] : 46;
@@ -54,9 +56,10 @@ public TokenSigner(Algorithms digestMethod, Derivation keyDerivation, byte[] sec
this.sep = sep;
}
- public TokenSigner(Algorithms digestMethod, Derivation keyDerivation, MessageDigestAlgorithm digest, byte[] secret_key, byte[] salt, byte sep) {
+ public TokenSigner(Algorithms digestMethod, Derivation keyDerivation, MessageDerivation messageDerivation, MessageDigestAlgorithm digest, byte[] secret_key, byte[] salt, byte sep) {
this.digestMethod = digestMethod;
this.keyDerivation = keyDerivation;
+ this.messageDerivation = messageDerivation;
this.messageDigestAlgorithm = digest;
this.secret_key = secret_key;
this.salt = salt;
@@ -79,6 +82,14 @@ public void setKeyDerivation(Derivation keyDerivation) {
this.keyDerivation = keyDerivation;
}
+ public void setMessageDerivation(MessageDerivation messageDerivation) {
+ this.messageDerivation = messageDerivation;
+ }
+
+ public MessageDerivation getMessageDerivation() {
+ return messageDerivation;
+ }
+
public MessageDigestAlgorithm getMessageDigestAlgorythm() {
return messageDigestAlgorithm;
}
@@ -112,6 +123,19 @@ public void setMessageDigestAlgorithm(MessageDigestAlgorithm messageDigestAlgori
this.messageDigestAlgorithm = messageDigestAlgorithm;
}
+ public byte[] derive_message(byte[] value) {
+ switch (messageDerivation){
+ case TORNADO -> {
+ return Bytes.concat(value, new byte[] {sep});
+ }
+ case CONCAT -> {
+ return Bytes.concat(Utils.split(value, sep));
+ }
+ default -> {
+ return value;
+ }
+ }
+ }
public byte[] derive_key() throws DerivationException {
try {
if (messageDigestAlgorithm == MessageDigestAlgorithm.NONE) return secret_key;
@@ -181,11 +205,12 @@ public byte[] get_signature_unsafe(byte[] value) throws Exception {
public byte[] get_signature_bytes(byte[] value) {
try {
+ byte[] message = derive_message(value);
byte[] key = derive_key();
SecretKeySpec signingKey = new SecretKeySpec(key, digestMethod.name);
Mac mac = Mac.getInstance(digestMethod.name);
mac.init(signingKey);
- return mac.doFinal(value);
+ return mac.doFinal(message);
} catch (Exception e) {
return new byte[]{};
}
@@ -244,7 +269,7 @@ public SecretKey getKey() {
String.valueOf((char) sep),
digestMethod,
keyDerivation,
- messageDigestAlgorithm);
+ messageDerivation, messageDigestAlgorithm);
}
@Override
@@ -253,6 +278,7 @@ public TokenSigner clone() {
TokenSigner clone = (TokenSigner) super.clone();
clone.setDigestMethod(clone.getDigestMethod());
clone.setKeyDerivation(clone.getKeyDerivation());
+ clone.setMessageDerivation(clone.getMessageDerivation());
clone.setMessageDigestAlgorithm(clone.getMessageDigestAlgorythm());
clone.setSep(clone.getSep());
clone.setSecretKey(clone.getSecretKey());
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/TornadoTokenSigner.java b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/TornadoTokenSigner.java
index 52c105c..2a0987b 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/crypto/TornadoTokenSigner.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/crypto/TornadoTokenSigner.java
@@ -14,7 +14,7 @@ public TornadoTokenSigner(SecretKey key) {
super(key);
}
public TornadoTokenSigner() {
- super(Algorithms.SHA1, Derivation.NONE, MessageDigestAlgorithm.NONE,new byte[] {}, new byte[] {}, (byte) '|');
+ super(Algorithms.SHA1, Derivation.NONE, MessageDerivation.NONE, MessageDigestAlgorithm.NONE,new byte[] {}, new byte[] {}, (byte) '|');
}
public TornadoTokenSigner( byte sep) {
super(new byte[] {}, sep);
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/model/DangerousSignedToken.java b/src/main/java/one/d4d/sessionless/itsdangerous/model/DangerousSignedToken.java
index a182e8e..ca8d334 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/model/DangerousSignedToken.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/model/DangerousSignedToken.java
@@ -28,6 +28,7 @@ public DangerousSignedToken(
String signature,
Algorithms algorithm,
Derivation derivation,
+ MessageDerivation messageDerivation,
MessageDigestAlgorithm digest) {
super(String.format("%s%c%s", payload, separator, timestamp));
this.separator = separator;
@@ -37,6 +38,7 @@ public DangerousSignedToken(
this.signer = new DangerousTokenSigner(
algorithm,
derivation,
+ messageDerivation,
digest,
new byte[]{},
new byte[]{},
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/model/DjangoSignedToken.java b/src/main/java/one/d4d/sessionless/itsdangerous/model/DjangoSignedToken.java
index 17634b1..0380398 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/model/DjangoSignedToken.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/model/DjangoSignedToken.java
@@ -2,13 +2,14 @@
import one.d4d.sessionless.itsdangerous.Algorithms;
import one.d4d.sessionless.itsdangerous.Derivation;
+import one.d4d.sessionless.itsdangerous.MessageDerivation;
import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
import one.d4d.sessionless.utils.Utils;
public class DjangoSignedToken extends DangerousSignedToken {
public DjangoSignedToken(byte separator, String payload, String timestamp, String signature) {
- super(separator, payload, timestamp, signature, Algorithms.SHA1, Derivation.DJANGO, MessageDigestAlgorithm.SHA1);
+ super(separator, payload, timestamp, signature, Algorithms.SHA1, Derivation.DJANGO, MessageDerivation.NONE, MessageDigestAlgorithm.SHA1);
}
@Override
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/model/SignedTokenObjectFinder.java b/src/main/java/one/d4d/sessionless/itsdangerous/model/SignedTokenObjectFinder.java
index d0a575c..6c333ef 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/model/SignedTokenObjectFinder.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/model/SignedTokenObjectFinder.java
@@ -2,6 +2,7 @@
import burp.api.montoya.http.message.Cookie;
import burp.api.montoya.http.message.params.ParsedHttpParameter;
+import burp.config.SignerConfig;
import com.google.common.base.CharMatcher;
import one.d4d.sessionless.utils.Utils;
import org.apache.commons.lang3.StringUtils;
@@ -12,32 +13,63 @@
import java.util.stream.Collectors;
public class SignedTokenObjectFinder {
- public final static char[] SEPARATORS = {'.', ':', '#', '|'};
- public final static char[] ALL_SEPARATORS = {'.', ':', '!', '#', '$', '*', ';', '@', '|', '~'};
+ public static final char[] SEPARATORS = {'.', ':', '#', '|'};
+ public static final char[] ALL_SEPARATORS = {'.', ':', '!', '#', '$', '*', ';', '@', '|', '~'};
+ private static final int[] SIGNATURES_LENGTH = {20, 28, 32, 48, 64};
private static final String SIGNED_PARAM = ".SIG";
// Regular expressions for JWS/JWE extraction
private static final String BASE64_REGEX = "[A-Za-z0-9-_]";
private static final String SEPARATOR_REGEX = "[.:!#$*;@|~]";
- private static final String SIGNER_REGEX = String.format("\\.?%s*%s+%s*%s+%s+", BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX); //NON-NLS
- private static final Pattern SIGNER_OBJECT_PATTERN = Pattern.compile(String.format("(%s)", SIGNER_REGEX)); //NON-NLS
+ private static final String SIGNER_REGEX = String.format("\\.?%s*%s+%s*%s+%s+", BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX);
+ private static final Pattern SIGNER_OBJECT_PATTERN = Pattern.compile(String.format("(%s)", SIGNER_REGEX));
+ private static final String UNKNOWN_SIGNED_STRING_REGEXP = String.format("(%s*%s%s{26,86})",BASE64_REGEX, SEPARATOR_REGEX, BASE64_REGEX);
+ private static final Pattern UNKNOWN_SIGNED_STRING_PATTERN = Pattern.compile(UNKNOWN_SIGNED_STRING_REGEXP);
-
- public static boolean containsSignedTokenObjects(String text, List cookies, List params) {
- List candidates = extractSignedTokenObjects(text, cookies, params);
+ public static boolean containsSignedTokenObjects(SignerConfig signerConfig, String text, List cookies, List params) {
+ List candidates = extractSignedTokenObjects(signerConfig, text, cookies, params);
return candidates.size() > 0;
}
- public static List extractSignedTokenObjects(String text, List cookies, List params) {
+ public static List extractSignedTokenObjects(SignerConfig signerConfig, String text, List cookies, List params) {
List signedTokensObjects = new ArrayList<>();
- Set candidates = findCandidateSignedTokenObjectsWithin(text);
-
- for (String candidate : candidates) {
- parseToken(candidate)
- .ifPresent(value ->
- signedTokensObjects.add(new MutableSignedToken(candidate, value)));
+ Map cookiesToHashMap = convertCookiesToHashMap(cookies);
+ Map paramsToHashMap = convertParamsToHashMap(params);
+ if (signerConfig.isEnableDangerous()) {
+ Set tokenCandidates = findCandidateSignedTokenObjectsWithin(text);
+ for (String candidate : tokenCandidates) {
+ parseToken(candidate)
+ .ifPresent(value ->
+ signedTokensObjects.add(new MutableSignedToken(candidate, value)));
+ }
+ }
+ if (signerConfig.isEnableExpress()) {
+ signedTokensObjects.addAll(parseExpressSignedParams(cookiesToHashMap));
+ signedTokensObjects.addAll(parseExpressSignedParams(paramsToHashMap));
+ }
+ if(signerConfig.isEnableOAuth()) {
+ cookiesToHashMap.forEach((name,value) -> {
+ parseOauthProxySignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ });
+ paramsToHashMap.forEach((name,value) -> {
+ parseOauthProxySignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ });
+ }
+ if(signerConfig.isEnableTornado()) {
+ cookiesToHashMap.forEach((name,value) -> {
+ parseTornadoSignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ });
+ paramsToHashMap.forEach((name,value) -> {
+ parseTornadoSignedToken(name, value).ifPresent(v -> signedTokensObjects.add(new MutableSignedToken(value, v)));
+ });
+ }
+ if(signerConfig.isEnableUnknown()) {
+ Set stringCandidates = findCandidateUnknownSignedStringWithin(text);
+ for (String candidate : stringCandidates) {
+ parseUnknownSignedString(candidate)
+ .ifPresent(value ->
+ signedTokensObjects.add(new MutableSignedToken(candidate, value)));
+ }
}
- signedTokensObjects.addAll(parseSignedTokenWithinHashMap(convertCookiesToHashMap(cookies)));
- signedTokensObjects.addAll(parseSignedTokenWithinHashMap(convertParamsToHashMap(params)));
return signedTokensObjects;
}
@@ -54,6 +86,17 @@ public static Set findCandidateSignedTokenObjectsWithin(String text) {
return strings;
}
+ public static Set findCandidateUnknownSignedStringWithin(String text) {
+ Matcher m = UNKNOWN_SIGNED_STRING_PATTERN.matcher(text);
+ Set strings = new HashSet<>();
+
+ while (m.find()) {
+ String token = m.group();
+ strings.add(token);
+ }
+
+ return strings;
+ }
public static Optional parseToken(String candidate) {
Optional dst = parseDjangoSignedToken(candidate);
return dst.isPresent() ? dst : parseDangerousSignedToken(candidate);
@@ -83,6 +126,32 @@ private static Map convertCookiesToHashMap(List cookies)
Cookie::value)
);
}
+ public static List parseExpressSignedParams(Map params) {
+ List signedTokensObjects = new ArrayList<>();
+ if (params != null) {
+ List signatures = params
+ .keySet()
+ .stream()
+ .filter(value -> value.toUpperCase().contains(SIGNED_PARAM))
+ .toList();
+ for (String signature : signatures) {
+ String sigValue = params.get(signature);
+ String signedParameter = signature.substring(0, signature.toUpperCase().indexOf(SIGNED_PARAM));
+ if(params.get(signedParameter) == null) continue;
+ String signedValue = params.get(signedParameter);
+ try {
+ Base64.getUrlDecoder().decode(signedValue);
+ } catch (Exception e) {
+ continue;
+ }
+ ExpressSignedToken t = new ExpressSignedToken(signedParameter, signedValue, sigValue);
+ signedTokensObjects.add(new MutableSignedToken(signedValue, t));
+
+ }
+ }
+
+ return signedTokensObjects;
+ }
public static List parseSignedTokenWithinHashMap(Map params) {
List signedTokensObjects = new ArrayList<>();
if (params != null) {
@@ -283,9 +352,8 @@ private static Optional parseDangerousSignedToken(String text) {
// Signature guesser
String signature = parts[2];
try {
- if (Utils.normalization(signature.getBytes()).length < 20) {
- return Optional.empty();
- }
+ int length = Utils.normalization(signature.getBytes()).length;
+ if(Arrays.stream(SIGNATURES_LENGTH).noneMatch(x -> x == length)) return Optional.empty();
} catch (Exception e) {
return Optional.empty();
}
@@ -323,9 +391,8 @@ public static Optional parseDjangoSignedToken(String text) {
// Signature guesser
String signature = parts[2];
try {
- if (Utils.normalization(signature.getBytes()).length < 20) {
- return Optional.empty();
- }
+ int length = Utils.normalization(signature.getBytes()).length;
+ if(Arrays.stream(SIGNATURES_LENGTH).noneMatch(x -> x == length)) return Optional.empty();
} catch (Exception e) {
return Optional.empty();
}
@@ -366,7 +433,8 @@ public static Optional parseJSONWebSignature(String text) {
// Signature parser
String signature = parts[2];
try {
- Utils.base64Decompress(signature.getBytes());
+ int length = Utils.base64Decompress(signature.getBytes()).length;
+ if(Arrays.stream(SIGNATURES_LENGTH).noneMatch(x -> x == length)) return Optional.empty();
} catch (Exception e) {
return Optional.empty();
}
@@ -374,4 +442,26 @@ public static Optional parseJSONWebSignature(String text) {
return Optional.of(t);
}
+
+ public static Optional parseUnknownSignedString(String text) {
+ char separator = 0;
+ for (char sep : SEPARATORS) {
+ if (CharMatcher.is(sep).countIn(text) > 0) {
+ separator = sep;
+ }
+ }
+ if (separator == 0) return Optional.empty();
+ int index = text.lastIndexOf(separator);
+ String message = text.substring(0,index);
+ String signature = text.substring(index + 1);
+ try {
+ int length = Utils.normalization(signature.getBytes()).length;
+ if(Arrays.stream(SIGNATURES_LENGTH).noneMatch(x -> x == length)) return Optional.empty();
+ } catch (Exception e) {
+ return Optional.empty();
+ }
+
+ UnknownSignedToken t = new UnknownSignedToken(message, signature, (byte) separator);
+ return Optional.of(t);
+ }
}
diff --git a/src/main/java/one/d4d/sessionless/itsdangerous/model/UnknownSignedToken.java b/src/main/java/one/d4d/sessionless/itsdangerous/model/UnknownSignedToken.java
index 2338eae..d8a08a2 100644
--- a/src/main/java/one/d4d/sessionless/itsdangerous/model/UnknownSignedToken.java
+++ b/src/main/java/one/d4d/sessionless/itsdangerous/model/UnknownSignedToken.java
@@ -1,6 +1,10 @@
package one.d4d.sessionless.itsdangerous.model;
import com.nimbusds.jwt.JWTClaimsSet;
+import one.d4d.sessionless.itsdangerous.Algorithms;
+import one.d4d.sessionless.itsdangerous.Derivation;
+import one.d4d.sessionless.itsdangerous.MessageDerivation;
+import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
import one.d4d.sessionless.itsdangerous.crypto.TokenSigner;
public class UnknownSignedToken extends SignedToken {
@@ -10,8 +14,15 @@ public UnknownSignedToken(String message, String signature, byte separator) {
super(message);
this.signature = signature;
this.separator = separator;
- this.signer = new TokenSigner(new byte[]{}, separator);
- }
+ this.signer = new TokenSigner(
+ Algorithms.SHA256,
+ Derivation.NONE,
+ MessageDerivation.NONE,
+ MessageDigestAlgorithm.NONE,
+ new byte[] {},
+ new byte[] {},
+ separator);
+ }
@Override
@@ -28,4 +39,7 @@ public void resign() throws Exception {
public void setClaims(JWTClaimsSet claims) {
}
+ public byte[] getSeparator() {
+ return new byte[]{separator};
+ }
}
diff --git a/src/main/java/one/d4d/sessionless/keys/SecretKey.java b/src/main/java/one/d4d/sessionless/keys/SecretKey.java
index d5e4488..a2cc9f2 100644
--- a/src/main/java/one/d4d/sessionless/keys/SecretKey.java
+++ b/src/main/java/one/d4d/sessionless/keys/SecretKey.java
@@ -4,6 +4,7 @@
import com.google.gson.annotations.SerializedName;
import one.d4d.sessionless.itsdangerous.Algorithms;
import one.d4d.sessionless.itsdangerous.Derivation;
+import one.d4d.sessionless.itsdangerous.MessageDerivation;
import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
public class SecretKey implements Key {
@@ -26,6 +27,9 @@ public class SecretKey implements Key {
@SerializedName("keyDerivation")
private final Derivation keyDerivation;
@Expose
+ @SerializedName("messageDerivation")
+ private final MessageDerivation messageDerivation;
+ @Expose
@SerializedName("messageDigestAlgorythm")
private final MessageDigestAlgorithm messageDigestAlgorithm;
@@ -36,6 +40,7 @@ public SecretKey(
String separator,
Algorithms digestMethod,
Derivation keyDerivation,
+ MessageDerivation messageDerivation,
MessageDigestAlgorithm messageDigestAlgorithm) {
this.keyId = keyId;
this.secret = secret;
@@ -43,6 +48,7 @@ public SecretKey(
this.separator = separator;
this.digestMethod = digestMethod;
this.keyDerivation = keyDerivation;
+ this.messageDerivation = messageDerivation;
this.messageDigestAlgorithm = messageDigestAlgorithm;
}
@@ -66,6 +72,10 @@ public Derivation getKeyDerivation() {
return keyDerivation;
}
+ public MessageDerivation getMessageDerivation() {
+ return messageDerivation;
+ }
+
public MessageDigestAlgorithm getMessageDigestAlgorythm() {
return messageDigestAlgorithm;
}
diff --git a/src/main/java/one/d4d/sessionless/presenter/EditorModel.java b/src/main/java/one/d4d/sessionless/presenter/EditorModel.java
index 0fb2420..32ee1cd 100644
--- a/src/main/java/one/d4d/sessionless/presenter/EditorModel.java
+++ b/src/main/java/one/d4d/sessionless/presenter/EditorModel.java
@@ -2,6 +2,7 @@
import burp.api.montoya.http.message.Cookie;
import burp.api.montoya.http.message.params.ParsedHttpParameter;
+import burp.config.SignerConfig;
import one.d4d.sessionless.itsdangerous.model.MutableSignedToken;
import one.d4d.sessionless.itsdangerous.model.SignedTokenObjectFinder;
import org.apache.commons.lang3.StringUtils;
@@ -11,6 +12,7 @@
import java.util.concurrent.atomic.AtomicInteger;
class EditorModel {
+ private final SignerConfig signerConfig;
private static final String SERIALIZED_OBJECT_FORMAT_STRING = "%d - %s";
private final List mutableSerializedObjects = new ArrayList<>();
@@ -18,11 +20,15 @@ class EditorModel {
private String message;
+ public EditorModel(SignerConfig signerConfig) {
+ this.signerConfig = signerConfig;
+ }
+
void setMessage(String content, List cookies, List params) {
synchronized (lock) {
message = content;
mutableSerializedObjects.clear();
- mutableSerializedObjects.addAll(SignedTokenObjectFinder.extractSignedTokenObjects(content,cookies,params));
+ mutableSerializedObjects.addAll(SignedTokenObjectFinder.extractSignedTokenObjects(signerConfig,content,cookies,params));
}
}
diff --git a/src/main/java/one/d4d/sessionless/presenter/EditorPresenter.java b/src/main/java/one/d4d/sessionless/presenter/EditorPresenter.java
index f1ca421..5374058 100644
--- a/src/main/java/one/d4d/sessionless/presenter/EditorPresenter.java
+++ b/src/main/java/one/d4d/sessionless/presenter/EditorPresenter.java
@@ -3,7 +3,7 @@
import burp.api.montoya.collaborator.CollaboratorPayloadGenerator;
import burp.api.montoya.http.message.Cookie;
import burp.api.montoya.http.message.params.ParsedHttpParameter;
-import com.nimbusds.jwt.JWTClaimsSet;
+import burp.config.SignerConfig;
import one.d4d.sessionless.forms.EditorTab;
import one.d4d.sessionless.forms.MessageDialogFactory;
import one.d4d.sessionless.forms.dialog.*;
@@ -22,6 +22,7 @@
public class EditorPresenter extends Presenter {
private final PresenterStore presenters;
+ private final SignerConfig signerConfig;
private final EditorModel model;
private final EditorTab view;
private final CollaboratorPayloadGenerator collaboratorPayloadGenerator;
@@ -34,14 +35,16 @@ public EditorPresenter(
EditorTab view,
CollaboratorPayloadGenerator collaboratorPayloadGenerator,
ErrorLoggingActionListenerFactory actionListenerFactory,
- PresenterStore presenters) {
+ PresenterStore presenters,
+ SignerConfig signerConfig) {
this.view = view;
- this.model = new EditorModel();
+ this.model = new EditorModel(signerConfig);
this.collaboratorPayloadGenerator = collaboratorPayloadGenerator;
this.actionListenerFactory = actionListenerFactory;
this.presenters = presenters;
messageDialogFactory = new MessageDialogFactory(view.uiComponent());
presenters.register(this);
+ this.signerConfig = signerConfig;
}
public void setMessage(String content, URL targetURL, List cookies, List params) {
@@ -158,6 +161,20 @@ private void setTornado(TornadoSignedToken token) {
view.setTornadoValue(token.getValue());
view.setTornadoSignature(token.getSignature());
}
+ private UnknownSignedToken getUnknown() {
+
+ String message = view.getUnknownMessage();
+ String signature = view.getUnknownSignature();
+ byte[] separator = view.getUnknownSeparator().length == 0 ? new byte[]{46} : view.getUnknownSeparator();
+
+ return new UnknownSignedToken(message,signature,separator[0]);
+ }
+
+ private void setUnknown(UnknownSignedToken token) {
+ view.setUnknownMessage(token.getEncodedMessage());
+ view.setUnknownSignature(token.getEncodedSignature());
+ view.setUnknownSeparator(token.getSeparator());
+ }
public void componentChanged() {
@@ -169,23 +186,7 @@ public void componentChanged() {
case EditorTab.TAB_EXPRESS -> tokenObject = getExpress();
case EditorTab.TAB_OAUTH -> tokenObject = getOAuth();
case EditorTab.TAB_TORNADO -> tokenObject = getTornado();
- default -> tokenObject = new SignedToken("Blank") {
- @Override
- public String serialize() {
- return null;
- }
-
-
- @Override
- public void resign() throws Exception {
-
- }
-
- @Override
- public void setClaims(JWTClaimsSet claims) {
-
- }
- };
+ default -> tokenObject = getUnknown();
}
mutableSignedTokenObject.setModified(tokenObject);
view.setSignedToken(tokenObject.serialize(), mutableSignedTokenObject.changed() && !selectionChanging);
@@ -209,6 +210,9 @@ public void onSelectionChanged() {
} else if (tokenObject instanceof TornadoSignedToken) {
view.setTornadoMode();
setTornado((TornadoSignedToken) tokenObject);
+ } else if (tokenObject instanceof UnknownSignedToken) {
+ view.setUnknownMode();
+ setUnknown((UnknownSignedToken) tokenObject);
}
selectionChanging = false;
}
@@ -258,6 +262,9 @@ private void attackDialog() {
} else if (signed instanceof TornadoSignedToken) {
view.setTornadoMode();
setTornado((TornadoSignedToken) signed);
+ } else if (signed instanceof UnknownSignedToken) {
+ view.setUnknownMode();
+ setUnknown((UnknownSignedToken) signed);
}
}
}
@@ -294,6 +301,9 @@ private void signingDialog() {
} else if (signed instanceof TornadoSignedToken) {
view.setTornadoMode();
setTornado((TornadoSignedToken) signed);
+ } else if (signed instanceof UnknownSignedToken) {
+ view.setUnknownMode();
+ setUnknown((UnknownSignedToken) signed);
}
}
}
@@ -322,6 +332,7 @@ public void onAttackClicked(Attack mode) {
actionListenerFactory,
attackKeys,
attackSalts,
+ keysPresenter.getSigningKeys(),
mode,
tokenObject);
bruteForceDialog.display();
@@ -340,6 +351,9 @@ public void onAttackClicked(Attack mode) {
}
}
+ public void onAttackKnownKeysClicked() {
+ onAttackClicked(Attack.KNOWN);
+ }
public void onAttackFastClicked() {
onAttackClicked(Attack.FAST);
}
@@ -353,7 +367,7 @@ public void onAttackDeepClicked() {
}
public boolean isEnabled(String text, List cookies, List params) {
- return containsSignedTokenObjects(text, cookies, params);
+ return containsSignedTokenObjects(signerConfig, text, cookies, params);
}
public String getMessage() {
diff --git a/src/main/resources/strings.properties b/src/main/resources/strings.properties
index 66723ee..dfe5386 100644
--- a/src/main/resources/strings.properties
+++ b/src/main/resources/strings.properties
@@ -33,6 +33,7 @@ error_title_no_secrets=Secrets not found!
error_no_secrets=Please add secrets at settings tab
error_title_no_salts=Salts not found!
error_no_salts=Please add salts at settings tab
+editor_view_button_attack_known_keys=Known keys
editor_view_button_attack_fast=Fast
editor_view_button_attack_balanced=Balanced
editor_view_button_attack_deep=Deep
@@ -55,6 +56,7 @@ table_id=ID
table_secret=Secret
table_algorithm=Algorithm
table_derivation=Derivation
+table_message_derivation=Message Derivation
table_digest=Digest
table_menu_delete=Delete
table_menu_copy=Copy
@@ -83,4 +85,13 @@ checkbox_user_access_token=User access_token
panel_signing_keys_label=Signing keys
checkbox_json_label=JSON
button_sign_label=Sign
-text_area_syntax_label=text/json
\ No newline at end of file
+text_area_syntax_label=text/json
+unknown_tab_lable=Unknown
+unknown_message_label=Message
+unknown_signature_label=Signature
+unknown_separator_label=Separator
+signer_settings_label=Enabled signers:
+key_dialog_digest=Digest
+key_dialog_message_derivation=Message derivation
+key_dialog_key_derivation=Key derivation
+key_dialog_algorythm=Algorythm
\ No newline at end of file
diff --git a/src/test/java/BruteForceTest.java b/src/test/java/BruteForceTest.java
index 7c599e2..d216b4a 100644
--- a/src/test/java/BruteForceTest.java
+++ b/src/test/java/BruteForceTest.java
@@ -7,6 +7,7 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -22,8 +23,9 @@ void BruteForceAttack() {
token.setSigner(s);
final List secrets = List.of("secret");
final List salts = List.of("salt");
+ final List knownKeys = new ArrayList<>();
- BruteForce bf = new BruteForce(secrets, salts, Attack.FAST, token);
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.FAST, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
} else {
@@ -42,8 +44,9 @@ void BruteForceMultiThreatAttack() {
token.setSigner(s);
final List secrets = List.of("secret");
final List salts = List.of("salt");
+ final List knownKeys = new ArrayList<>();
- BruteForce bf = new BruteForce(secrets, salts, Attack.FAST, token);
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.FAST, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
} else {
diff --git a/src/test/java/ClaimsTest.java b/src/test/java/ClaimsTest.java
index 76eeb4a..7f1fb15 100644
--- a/src/test/java/ClaimsTest.java
+++ b/src/test/java/ClaimsTest.java
@@ -1,6 +1,7 @@
import com.nimbusds.jwt.JWTClaimsSet;
import one.d4d.sessionless.itsdangerous.Algorithms;
import one.d4d.sessionless.itsdangerous.Derivation;
+import one.d4d.sessionless.itsdangerous.MessageDerivation;
import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
import one.d4d.sessionless.keys.SecretKey;
import one.d4d.sessionless.utils.ClaimsUtils;
@@ -69,7 +70,15 @@ void AccountUserPayloadTest() {
@Test
void UserAccessTokenPayloadTest() {
try {
- SecretKey key = new SecretKey("1", "secret", "",".", Algorithms.SHA256, Derivation.NONE, MessageDigestAlgorithm.NONE);
+ SecretKey key = new SecretKey(
+ "1",
+ "secret",
+ "",
+ ".",
+ Algorithms.SHA256,
+ Derivation.NONE,
+ MessageDerivation.NONE,
+ MessageDigestAlgorithm.NONE);
URL target = new URL("https://d4d.one/");
ClaimsUtils.generateUserAccessTokenPayload(target, key);
} catch (MalformedURLException e) {
diff --git a/src/test/java/CompressTest.java b/src/test/java/CompressTest.java
index b51a257..55e89e7 100644
--- a/src/test/java/CompressTest.java
+++ b/src/test/java/CompressTest.java
@@ -15,6 +15,5 @@ void Base64EncodedTimestampTest() {
}catch (Exception e) {
fail(e.getMessage());
}
-
}
}
diff --git a/src/test/java/DjangoTest.java b/src/test/java/DjangoTest.java
index 549f34c..f955fe9 100644
--- a/src/test/java/DjangoTest.java
+++ b/src/test/java/DjangoTest.java
@@ -11,6 +11,7 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -20,12 +21,13 @@ public class DjangoTest {
void DjangoBruteForceTest() {
List signingSecrets = List.of("secret");
List signingSalts = List.of("django.contrib.sessions.backends.signed_cookies");
+ List knownKeys = new ArrayList<>();
Attack mode = Attack.Deep;
String value = "gAWVMwAAAAAAAAB9lIwKdGVzdGNvb2tpZZSMBXBvc2l4lIwGc3lzdGVtlJOUjAhzbGVlcCAzMJSFlFKUcy4:1rBDnz:6RroyItcbm4P82lx2kEAuV2ykxs";
Optional optionalToken = SignedTokenObjectFinder.parseToken(value);
if (optionalToken.isPresent()) {
DangerousSignedToken token = (DangerousSignedToken) optionalToken.get();
- BruteForce bf = new BruteForce(signingSecrets, signingSalts, mode, token);
+ BruteForce bf = new BruteForce(signingSecrets, signingSalts, knownKeys, mode, token);
SecretKey k = bf.search();
Assertions.assertNotNull(k);
} else {
diff --git a/src/test/java/JSONWebSignatureTest.java b/src/test/java/JSONWebSignatureTest.java
index d2f717b..f9717f7 100644
--- a/src/test/java/JSONWebSignatureTest.java
+++ b/src/test/java/JSONWebSignatureTest.java
@@ -9,6 +9,7 @@
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -17,11 +18,12 @@ public class JSONWebSignatureTest {
void JSONWebSignatureParserTest() {
final List secrets = List.of("your-256-bit-secret");
final List salts = List.of("salt");
+ final List knownKeys = new ArrayList<>();
String value = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
Optional optionalToken = SignedTokenObjectFinder.parseJSONWebSignature(value);
if (optionalToken.isPresent()) {
JSONWebSignature token = (JSONWebSignature) optionalToken.get();
- BruteForce bf = new BruteForce(secrets, salts, Attack.FAST, token);
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.FAST, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
} else {
@@ -33,13 +35,14 @@ void JSONWebSignatureClaimsTest() {
try {
final List secrets = List.of("secret");
final List salts = List.of("salt");
+ final List knownKeys = new ArrayList<>();
URL target = new URL("https://d4d.one/");
- SecretKey key = new SecretKey("1", "secret", "",".", Algorithms.SHA256, Derivation.NONE, MessageDigestAlgorithm.NONE);
+ SecretKey key = new SecretKey("1", "secret", "",".", Algorithms.SHA256, Derivation.NONE, MessageDerivation.NONE, MessageDigestAlgorithm.NONE);
String value = ClaimsUtils.generateJSONWebToken(target, ClaimsUtils.DEFAULT_USERNAME, key);
Optional optionalToken = SignedTokenObjectFinder.parseJSONWebSignature(value);
if (optionalToken.isPresent()) {
JSONWebSignature token = (JSONWebSignature) optionalToken.get();
- BruteForce bf = new BruteForce(secrets, salts, Attack.FAST, token);
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.FAST, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
} else {
diff --git a/src/test/java/KeyPersistenceStoreTest.java b/src/test/java/KeyPersistenceStoreTest.java
index 8f43741..274ced7 100644
--- a/src/test/java/KeyPersistenceStoreTest.java
+++ b/src/test/java/KeyPersistenceStoreTest.java
@@ -2,6 +2,7 @@
import com.google.gson.Gson;
import one.d4d.sessionless.itsdangerous.Algorithms;
import one.d4d.sessionless.itsdangerous.Derivation;
+import one.d4d.sessionless.itsdangerous.MessageDerivation;
import one.d4d.sessionless.itsdangerous.MessageDigestAlgorithm;
import one.d4d.sessionless.keys.SecretKey;
import one.d4d.sessionless.utils.GsonHelper;
@@ -16,7 +17,7 @@ void KeyDerivationTest() {
KeysModel model = new KeysModel();
model.setSalts(Utils.readResourceForClass("/salts", this.getClass()));
model.setSecrets(Utils.readResourceForClass("/secrets", this.getClass()));
- model.addKey(new SecretKey("test", "secret","salt",".", Algorithms.SHA1, Derivation.HMAC, MessageDigestAlgorithm.SHA1));
+ model.addKey(new SecretKey("test", "secret","salt",".", Algorithms.SHA1, Derivation.HMAC, MessageDerivation.NONE, MessageDigestAlgorithm.SHA1));
Gson gson = GsonHelper.customGson;
String serial = gson.toJson(model);
diff --git a/src/test/java/SignUnsignTest.java b/src/test/java/SignUnsignTest.java
index 70f4567..1c4dcc0 100644
--- a/src/test/java/SignUnsignTest.java
+++ b/src/test/java/SignUnsignTest.java
@@ -8,6 +8,7 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -30,8 +31,9 @@ void KeyDerivationTest() {
token.setSigner(s);
final List secrets = List.of("secret");
final List salts = List.of("cookie-session");
+ final List knownKeys = new ArrayList<>();
- BruteForce bf = new BruteForce(secrets, salts, Attack.Deep, token);
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.Deep, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
}
diff --git a/src/test/java/TornadoTest.java b/src/test/java/TornadoTest.java
index adf8b30..2288fcc 100644
--- a/src/test/java/TornadoTest.java
+++ b/src/test/java/TornadoTest.java
@@ -9,6 +9,7 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -40,8 +41,9 @@ void BruteForceMultiThreatTornado() {
optionalToken.get().setSigner(s);
final List secrets = Utils.readResourceForClass("/secrets", this.getClass());
final List salts = Utils.readResourceForClass("/salts", this.getClass());
+ final List knownKeys = new ArrayList<>();
- BruteForce bf = new BruteForce(secrets, salts, Attack.FAST, optionalToken.get());
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.FAST, optionalToken.get());
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
}
diff --git a/src/test/java/UnknownSignedTokenTest.java b/src/test/java/UnknownSignedTokenTest.java
index 5d78bcb..4c033f8 100644
--- a/src/test/java/UnknownSignedTokenTest.java
+++ b/src/test/java/UnknownSignedTokenTest.java
@@ -1,13 +1,17 @@
import com.google.common.collect.Lists;
import one.d4d.sessionless.itsdangerous.*;
import one.d4d.sessionless.itsdangerous.crypto.DjangoTokenSigner;
+import one.d4d.sessionless.itsdangerous.model.SignedToken;
+import one.d4d.sessionless.itsdangerous.model.SignedTokenObjectFinder;
import one.d4d.sessionless.itsdangerous.model.UnknownSignedToken;
import one.d4d.sessionless.keys.SecretKey;
import one.d4d.sessionless.utils.Utils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Optional;
public class UnknownSignedTokenTest {
@Test
@@ -19,7 +23,7 @@ void DjangoSignerTest() {
"eyJtZXNzYWdlIjoiSGVsbG8hIn0",
"V1O2qShdoisLMx2d0JTmVQecu8zsLPeXmTM5Id3ll",
(byte)':');
- DjangoTokenSigner s = new DjangoTokenSigner(Algorithms.SHA256, Derivation.DJANGO, MessageDigestAlgorithm.SHA256,secret, salt, (byte) ':');
+ DjangoTokenSigner s = new DjangoTokenSigner(Algorithms.SHA256, Derivation.DJANGO, MessageDerivation.NONE, MessageDigestAlgorithm.SHA256,secret, salt, (byte) ':');
token.setSigner(s);
Assertions.assertDoesNotThrow( ()-> {
s.unsign(value.getBytes());
@@ -35,8 +39,9 @@ void DjangoSignedMessageSaltDictionaryTest() {
(byte)':');
final List secrets = Utils.readResourceForClass("/secrets", this.getClass());
final List salts = Utils.readResourceForClass("/salts", this.getClass());
+ final List knownKeys = new ArrayList<>();
secrets.add(secret);
- BruteForce bf = new BruteForce(secrets, salts, Attack.Balanced, token);
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.Balanced, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
}
@@ -49,8 +54,9 @@ void DjangoSignedMessageBruteForceTest() {
(byte)':');
final List secrets = Utils.readResourceForClass("/secrets", this.getClass());
final List salts = Utils.readResourceForClass("/salts", this.getClass());
+ final List knownKeys = new ArrayList<>();
secrets.add(secret);
- BruteForce bf = new BruteForce(secrets, salts, Attack.Balanced, token);
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.Balanced, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
}
@@ -62,7 +68,8 @@ void URLSafeSerializerTest() {
(byte)'.');
final List secrets = Lists.newArrayList("secret key");
final List salts = Lists.newArrayList("auth");
- BruteForce bf = new BruteForce(secrets, salts, Attack.Balanced, token);
+ final List knownKeys = new ArrayList<>();
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.Balanced, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
}
@@ -74,7 +81,8 @@ void ItsDangerousSignerTest() {
(byte)'.');
final List secrets = Lists.newArrayList("secret-key");
final List salts = Lists.newArrayList("itsdangerous.Signer");
- BruteForce bf = new BruteForce(secrets, salts, Attack.Balanced, token);
+ final List knownKeys = new ArrayList<>();
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.Balanced, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
}
@@ -86,8 +94,25 @@ void RedashURLSafeTimedSerializerTest() {
(byte)'.');
final List secrets = Lists.newArrayList("c292a0a3aa32397cdb050e233733900f");
final List salts = Lists.newArrayList("itsdangerous");
- BruteForce bf = new BruteForce(secrets, salts, Attack.Balanced, token);
+ final List knownKeys = new ArrayList<>();
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.Balanced, token);
SecretKey sk = bf.search();
Assertions.assertNotNull(sk);
}
+ @Test
+ void UnknownSignedStringParserTest() {
+ final List secrets = List.of("c292a0a3aa32397cdb050e233733900f");
+ final List salts = List.of("itsdangerous");
+ final List knownKeys = new ArrayList<>();
+ String value = "IjEi.YhAmmQ.cdQp7CnnVq02aQ05y8tSBddl-qs";
+ Optional optionalToken = SignedTokenObjectFinder.parseUnknownSignedString(value);
+ if (optionalToken.isPresent()) {
+ UnknownSignedToken token = (UnknownSignedToken) optionalToken.get();
+ BruteForce bf = new BruteForce(secrets, salts, knownKeys, Attack.Balanced, token);
+ SecretKey sk = bf.search();
+ Assertions.assertNotNull(sk);
+ } else {
+ Assertions.fail("Token not found.");
+ }
+ }
}