From fcab9111d873801a5972807c9f1da3b927d2ddc9 Mon Sep 17 00:00:00 2001 From: ddwightx Date: Sun, 11 Dec 2022 18:40:38 -0500 Subject: [PATCH] Switched to the Montoya API. Added support for WebSockets. Added new When constraints: Message Type (WebSockets only). Added new Then actions: Intercept, Send Message (WebSockets ony). Added ignore case to When Matches Text. Added more details to Then and When lists. Added variable tags for annotations (i.e. comments and highlights). Added Session variable type for WebSockets. Added supported for exporting and importing data as YAML. Added right-click option for Rules in the Rules List to enable debug logging for specific Rules. --- .gitignore | 1 + build.gradle | 17 +- docs/Examples.md | 14 +- docs/MessageValues.md | 66 ++- docs/Readme.md | 78 +-- docs/Rules.md | 452 +++++++++++------- docs/ScriptingLibrary.md | 45 +- docs/Variables.md | 14 +- docs/_config.yml | 2 +- gradlew | 257 ++++++---- src/main/java/burp/BurpExtender.java | 78 ++- .../synfron/reshaper/burp/core/BurpTool.java | 40 +- .../synfron/reshaper/burp/core/Connector.java | 249 ---------- .../reshaper/burp/core/HttpConnector.java | 370 ++++++++++++++ .../reshaper/burp/core/InterceptResponse.java | 22 + .../reshaper/burp/core/ProtocolType.java | 27 ++ .../burp/core/WebSocketConnector.java | 211 ++++++++ .../burp/core/messages/ContentType.java | 16 +- .../reshaper/burp/core/messages/Encoder.java | 4 +- .../burp/core/messages/EventInfo.java | 152 ++---- ...aDirection.java => HttpDataDirection.java} | 2 +- .../burp/core/messages/HttpEventInfo.java | 143 ++++++ .../burp/core/messages/IEventInfo.java | 57 --- .../burp/core/messages/MessageAnnotation.java | 21 + .../burp/core/messages/MessageValue.java | 125 +++-- .../core/messages/MessageValueHandler.java | 58 ++- .../reshaper/burp/core/messages/MimeType.java | 22 +- .../core/messages/WebSocketDataDirection.java | 22 + .../core/messages/WebSocketEventInfo.java | 68 +++ .../core/messages/WebSocketMessageType.java | 6 + .../entities/{ => http}/HttpBody.java | 2 +- .../entities/{ => http}/HttpCookies.java | 2 +- .../entities/{ => http}/HttpEntity.java | 2 +- .../entities/{ => http}/HttpHeaders.java | 2 +- .../{ => http}/HttpRequestHeaders.java | 2 +- .../{ => http}/HttpRequestMessage.java | 71 +-- .../{ => http}/HttpRequestQueryParams.java | 2 +- .../{ => http}/HttpRequestStatusLine.java | 2 +- .../entities/{ => http}/HttpRequestUri.java | 3 +- .../{ => http}/HttpResponseHeaders.java | 2 +- .../{ => http}/HttpResponseMessage.java | 67 +-- .../{ => http}/HttpResponseStatusLine.java | 2 +- .../entities/websocket/WebSocketMessage.java | 4 + .../burp/core/rules/IHttpRuleOperation.java | 4 + .../burp/core/rules/IRuleOperation.java | 16 +- .../core/rules/IWebSocketRuleOperation.java | 4 + .../reshaper/burp/core/rules/Rule.java | 11 +- .../reshaper/burp/core/rules/RulesEngine.java | 22 +- .../core/rules/diagnostics/Diagnostics.java | 60 ++- .../core/rules/diagnostics/IDiagnostics.java | 16 +- .../reshaper/burp/core/rules/thens/Then.java | 24 +- .../burp/core/rules/thens/ThenBreak.java | 8 +- .../rules/thens/ThenBuildHttpMessage.java | 29 +- .../burp/core/rules/thens/ThenComment.java | 11 +- .../burp/core/rules/thens/ThenDelay.java | 8 +- .../core/rules/thens/ThenDeleteValue.java | 9 +- .../core/rules/thens/ThenDeleteVariable.java | 15 +- .../burp/core/rules/thens/ThenDrop.java | 8 +- .../burp/core/rules/thens/ThenEvaluate.java | 33 +- .../burp/core/rules/thens/ThenHighlight.java | 42 +- .../burp/core/rules/thens/ThenIntercept.java | 30 ++ .../burp/core/rules/thens/ThenLog.java | 8 +- .../rules/thens/ThenParseHttpMessage.java | 35 +- .../burp/core/rules/thens/ThenPrompt.java | 25 +- .../burp/core/rules/thens/ThenRunProcess.java | 26 +- .../burp/core/rules/thens/ThenRunRules.java | 23 +- .../burp/core/rules/thens/ThenRunScript.java | 8 +- .../burp/core/rules/thens/ThenSaveFile.java | 8 +- .../core/rules/thens/ThenSendMessage.java | 39 ++ .../core/rules/thens/ThenSendRequest.java | 62 +-- .../burp/core/rules/thens/ThenSendTo.java | 72 +-- .../burp/core/rules/thens/ThenSet.java | 11 +- .../core/rules/thens/ThenSetEncoding.java | 9 +- .../rules/thens/ThenSetEventDirection.java | 14 +- .../burp/core/rules/thens/ThenSetValue.java | 15 +- .../core/rules/thens/ThenSetVariable.java | 16 +- .../burp/core/rules/thens/ThenType.java | 6 +- .../buildhttpmessage/MessageValueSetter.java | 7 +- .../parsehttpmessage/MessageValueGetter.java | 7 +- .../thens/entities/script/ReshaperObj.java | 60 ++- .../entities/script/XmlHttpRequestObj.java | 32 +- .../thens/entities/sendto/SendToOption.java | 2 +- .../reshaper/burp/core/rules/whens/When.java | 9 +- .../core/rules/whens/WhenContentType.java | 10 +- .../core/rules/whens/WhenEventDirection.java | 18 +- .../burp/core/rules/whens/WhenFromTool.java | 8 +- .../burp/core/rules/whens/WhenHasEntity.java | 29 +- .../burp/core/rules/whens/WhenInScope.java | 13 +- .../core/rules/whens/WhenMatchesText.java | 32 +- .../core/rules/whens/WhenMessageType.java | 27 ++ .../burp/core/rules/whens/WhenMimeType.java | 11 +- .../burp/core/rules/whens/WhenProxyName.java | 12 +- .../burp/core/rules/whens/WhenType.java | 8 +- .../whens/WhenWebSocketEventDirection.java | 25 + .../burp/core/settings/ExportSettings.java | 1 + .../burp/core/settings/GeneralSettings.java | 12 +- .../burp/core/settings/SettingsManager.java | 44 +- .../reshaper/burp/core/settings/Storage.java | 4 +- .../synfron/reshaper/burp/core/utils/Log.java | 24 +- .../reshaper/burp/core/utils/ObjectUtils.java | 12 - .../reshaper/burp/core/utils/Protocol.java | 42 ++ .../reshaper/burp/core/utils/Serializer.java | 72 ++- .../reshaper/burp/core/utils/TextUtils.java | 8 +- .../synfron/reshaper/burp/core/utils/Url.java | 80 ++++ .../reshaper/burp/core/utils/UrlUtils.java | 13 + .../burp/core/vars/VariableSource.java | 30 +- .../burp/core/vars/VariableString.java | 77 +-- .../burp/ui/components/IFormComponent.java | 18 +- .../burp/ui/components/LogsComponent.java | 9 +- .../burp/ui/components/ReshaperComponent.java | 17 +- .../ui/components/rules/RuleComponent.java | 23 +- .../rules/RuleContainerComponent.java | 8 +- .../components/rules/RuleListComponent.java | 85 +++- .../rules/RuleOperationComponent.java | 6 +- .../RuleOperationContainerComponent.java | 8 +- .../rules/RuleOperationListComponent.java | 10 +- .../rules/RuleOperationsComponent.java | 6 +- .../RuleOperationsContainerComponent.java | 9 +- .../components/rules/RulesTabComponent.java | 11 +- .../rules/thens/ThenBreakComponent.java | 5 +- .../thens/ThenBuildHttpMessageComponent.java | 15 +- .../rules/thens/ThenCommentComponent.java | 5 +- .../components/rules/thens/ThenComponent.java | 5 +- .../rules/thens/ThenContainerComponent.java | 8 +- .../rules/thens/ThenDelayComponent.java | 5 +- .../rules/thens/ThenDeleteValueComponent.java | 24 +- .../thens/ThenDeleteVariableComponent.java | 7 +- .../rules/thens/ThenDropComponent.java | 5 +- .../rules/thens/ThenEvaluateComponent.java | 7 +- .../rules/thens/ThenHighlightComponent.java | 5 +- .../rules/thens/ThenInterceptComponent.java | 33 ++ .../rules/thens/ThenListComponent.java | 11 +- .../rules/thens/ThenLogComponent.java | 5 +- .../thens/ThenParseHttpMessageComponent.java | 17 +- .../rules/thens/ThenPromptComponent.java | 7 +- .../rules/thens/ThenRunProcessComponent.java | 7 +- .../rules/thens/ThenRunRulesComponent.java | 20 +- .../rules/thens/ThenRunScriptComponent.java | 5 +- .../rules/thens/ThenSaveFileComponent.java | 5 +- .../rules/thens/ThenSendMessageComponent.java | 44 ++ .../rules/thens/ThenSendRequestComponent.java | 7 +- .../rules/thens/ThenSendToComponent.java | 14 +- .../rules/thens/ThenSetComponent.java | 9 +- .../rules/thens/ThenSetEncodingComponent.java | 5 +- .../thens/ThenSetEventDirectionComponent.java | 13 +- .../rules/thens/ThenSetValueComponent.java | 9 +- .../rules/thens/ThenSetVariableComponent.java | 7 +- .../rules/thens/ThensComponent.java | 10 +- .../MessageValueSetterComponent.java | 9 +- .../MessageValueGetterComponent.java | 13 +- .../components/rules/whens/WhenComponent.java | 5 +- .../rules/whens/WhenContainerComponent.java | 8 +- .../rules/whens/WhenContentTypeComponent.java | 5 +- .../whens/WhenEventDirectionComponent.java | 13 +- .../rules/whens/WhenFromToolComponent.java | 5 +- .../rules/whens/WhenHasEntityComponent.java | 10 +- .../rules/whens/WhenInScopeComponent.java | 5 +- .../rules/whens/WhenListComponent.java | 11 +- .../rules/whens/WhenMatchesTextComponent.java | 19 +- .../rules/whens/WhenMessageTypeComponent.java | 34 ++ .../rules/whens/WhenMimeTypeComponent.java | 5 +- .../rules/whens/WhenProxyNameComponent.java | 5 +- .../WhenWebSocketEventDirectionComponent.java | 34 ++ .../rules/whens/WhensComponent.java | 10 +- .../AnnotationVariableTagWizardComponent.java | 35 ++ .../MessageVariableTagWizardComponent.java | 10 +- .../SessionVariableTagWizardComponent.java | 34 ++ .../VariableTagWizardContainerComponent.java | 10 +- .../vars/VariableTagWizardOptionPane.java | 14 +- .../wizard/whens/WhenWizardItemComponent.java | 5 +- .../settings/SettingsTabComponent.java | 143 ++++-- .../ui/components/vars/VariableComponent.java | 16 +- .../burp/ui/models/rules/RuleModel.java | 33 +- .../ui/models/rules/RuleOperationModel.java | 34 +- .../models/rules/RuleOperationModelType.java | 22 +- .../ui/models/rules/thens/ThenBreakModel.java | 10 +- .../thens/ThenBuildHttpMessageModel.java | 16 +- .../models/rules/thens/ThenCommentModel.java | 12 +- .../ui/models/rules/thens/ThenDelayModel.java | 10 +- .../rules/thens/ThenDeleteValueModel.java | 13 +- .../rules/thens/ThenDeleteVariableModel.java | 11 +- .../ui/models/rules/thens/ThenDropModel.java | 10 +- .../models/rules/thens/ThenEvaluateModel.java | 10 +- .../rules/thens/ThenHighlightModel.java | 10 +- .../rules/thens/ThenInterceptModel.java | 51 ++ .../ui/models/rules/thens/ThenLogModel.java | 12 +- .../burp/ui/models/rules/thens/ThenModel.java | 13 +- .../ui/models/rules/thens/ThenModelType.java | 63 +-- .../thens/ThenParseHttpMessageModel.java | 16 +- .../models/rules/thens/ThenPromptModel.java | 10 +- .../rules/thens/ThenRunProcessModel.java | 10 +- .../models/rules/thens/ThenRunRulesModel.java | 10 +- .../rules/thens/ThenRunScriptModel.java | 10 +- .../models/rules/thens/ThenSaveFileModel.java | 10 +- .../rules/thens/ThenSendMessageModel.java | 62 +++ .../rules/thens/ThenSendRequestModel.java | 5 +- .../models/rules/thens/ThenSendToModel.java | 10 +- .../rules/thens/ThenSetEncodingModel.java | 12 +- .../thens/ThenSetEventDirectionModel.java | 16 +- .../ui/models/rules/thens/ThenSetModel.java | 8 +- .../models/rules/thens/ThenSetValueModel.java | 13 +- .../rules/thens/ThenSetVariableModel.java | 10 +- .../rules/whens/WhenContentTypeModel.java | 10 +- .../rules/whens/WhenEventDirectionModel.java | 16 +- .../models/rules/whens/WhenFromToolModel.java | 10 +- .../rules/whens/WhenHasEntityModel.java | 13 +- .../models/rules/whens/WhenInScopeModel.java | 11 +- .../rules/whens/WhenMatchesTextModel.java | 22 +- .../rules/whens/WhenMessageTypeModel.java | 50 ++ .../models/rules/whens/WhenMimeTypeModel.java | 10 +- .../burp/ui/models/rules/whens/WhenModel.java | 13 +- .../ui/models/rules/whens/WhenModelType.java | 33 +- .../rules/whens/WhenProxyNameModel.java | 10 +- .../WhenWebSocketEventDirectionModel.java | 50 ++ .../AnnotationVariableTagWizardModel.java | 50 ++ .../vars/CookieJarVariableTagWizardModel.java | 24 +- .../vars/SessionVariableTagWizardModel.java | 66 +++ .../wizard/vars/VariableTagWizardModel.java | 4 +- .../wizard/whens/WhenWizardItemModel.java | 10 +- .../rules/wizard/whens/WhenWizardModel.java | 12 +- .../burp/ui/utils/ContextMenuHandler.java | 20 +- 221 files changed, 4321 insertions(+), 1890 deletions(-) delete mode 100644 src/main/java/synfron/reshaper/burp/core/Connector.java create mode 100644 src/main/java/synfron/reshaper/burp/core/HttpConnector.java create mode 100644 src/main/java/synfron/reshaper/burp/core/InterceptResponse.java create mode 100644 src/main/java/synfron/reshaper/burp/core/ProtocolType.java create mode 100644 src/main/java/synfron/reshaper/burp/core/WebSocketConnector.java rename src/main/java/synfron/reshaper/burp/core/messages/{DataDirection.java => HttpDataDirection.java} (69%) create mode 100644 src/main/java/synfron/reshaper/burp/core/messages/HttpEventInfo.java delete mode 100644 src/main/java/synfron/reshaper/burp/core/messages/IEventInfo.java create mode 100644 src/main/java/synfron/reshaper/burp/core/messages/MessageAnnotation.java create mode 100644 src/main/java/synfron/reshaper/burp/core/messages/WebSocketDataDirection.java create mode 100644 src/main/java/synfron/reshaper/burp/core/messages/WebSocketEventInfo.java create mode 100644 src/main/java/synfron/reshaper/burp/core/messages/WebSocketMessageType.java rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpBody.java (92%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpCookies.java (98%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpEntity.java (57%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpHeaders.java (98%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpRequestHeaders.java (75%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpRequestMessage.java (58%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpRequestQueryParams.java (96%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpRequestStatusLine.java (96%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpRequestUri.java (96%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpResponseHeaders.java (76%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpResponseMessage.java (55%) rename src/main/java/synfron/reshaper/burp/core/messages/entities/{ => http}/HttpResponseStatusLine.java (96%) create mode 100644 src/main/java/synfron/reshaper/burp/core/messages/entities/websocket/WebSocketMessage.java create mode 100644 src/main/java/synfron/reshaper/burp/core/rules/IHttpRuleOperation.java create mode 100644 src/main/java/synfron/reshaper/burp/core/rules/IWebSocketRuleOperation.java create mode 100644 src/main/java/synfron/reshaper/burp/core/rules/thens/ThenIntercept.java create mode 100644 src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendMessage.java create mode 100644 src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMessageType.java create mode 100644 src/main/java/synfron/reshaper/burp/core/rules/whens/WhenWebSocketEventDirection.java create mode 100644 src/main/java/synfron/reshaper/burp/core/utils/Protocol.java create mode 100644 src/main/java/synfron/reshaper/burp/core/utils/Url.java create mode 100644 src/main/java/synfron/reshaper/burp/core/utils/UrlUtils.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenInterceptComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendMessageComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMessageTypeComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenWebSocketEventDirectionComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/AnnotationVariableTagWizardComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SessionVariableTagWizardComponent.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenInterceptModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendMessageModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMessageTypeModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenWebSocketEventDirectionModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/AnnotationVariableTagWizardModel.java create mode 100644 src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionVariableTagWizardModel.java diff --git a/.gitignore b/.gitignore index eed5590..652e10c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .idea/ build/ gradle/ +reshaperTest.txt diff --git a/build.gradle b/build.gradle index 5637d3a..6498a76 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { } group 'com.synfron.reshaper.burp' -version '1.8.3' +version '2.0.0' targetCompatibility = '15' sourceCompatibility = '15' @@ -14,25 +14,26 @@ repositories { dependencies { testImplementation 'junit:junit:4.13.2' - testImplementation 'org.mockito:mockito-core:4.2.0' implementation 'org.apache.httpcomponents:httpclient:4.5.13' implementation 'org.mozilla:rhino:1.7.14' implementation 'cat.inspiracio:rhino-js-engine:1.7.10' - implementation 'org.apache.commons:commons-text:1.9' implementation 'commons-io:commons-io:2.11.0' implementation 'org.apache.commons:commons-lang3:3.12.0' implementation 'net.jodah:expiringmap:0.5.10' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2.2' implementation 'com.miglayout:miglayout-swing:11.0' - implementation 'org.jsoup:jsoup:1.14.3' implementation 'com.jayway.jsonpath:json-path:2.7.0' - implementation 'net.portswigger.burp.extender:burp-extender-api:2.3' implementation 'org.rypt:f8:1.1-RC1' implementation 'org.apache.commons:commons-csv:1.9.0' implementation 'com.alexandriasoftware.swing:jsplitbutton:1.3.1' implementation files('libs/htmlchardet-1.0.2.1.jar') - compileOnly 'org.projectlombok:lombok:1.18.22' - annotationProcessor 'org.projectlombok:lombok:1.18.22' + implementation 'org.jsoup:jsoup:1.15.3' + compileOnly 'org.projectlombok:lombok:1.18.24' + annotationProcessor 'org.projectlombok:lombok:1.18.24' + implementation 'net.portswigger.burp.extensions:montoya-api:0.10.1' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.0' + testImplementation 'org.mockito:mockito-core:4.8.0' + implementation 'org.apache.commons:commons-text:1.10.0' } jar { diff --git a/docs/Examples.md b/docs/Examples.md index d690f85..cc6a0c9 100644 --- a/docs/Examples.md +++ b/docs/Examples.md @@ -4,7 +4,7 @@ - [Redirect a request to a different server](#tip2) - [Change a value in a returned response](#tip3) - [Auto-respond to requests without first sending a request to an external server (response mocking)](#tip4) -- [Drop a request so it is not sent to an external server (Works on all supported tools: Proxy, Repeater, Intruder, Scanner, Spider, Target, Extender (other extensions))](#tip5) +- [Drop a request so it is not sent to an external server (Works on all supported tools: Proxy, Repeater, Intruder, Scanner, Target, Extender (other extensions))](#tip5) - [Share or backup/restore Global Variables and Rules](#tip6) @@ -12,7 +12,7 @@ In the example below, we are taking the `Authorization` header from `www.example.org` requests, storing it in a variable, and setting it on `www.example.com` requests. -1. Open the `Rules` tab. +1. Open the `HTTP Rules` tab. 2. Create a Rule. 3. Set the `Rule Name` to `Get www.example.org Authorization`. 4. Add When -> `Event Direction` (if not already added). @@ -43,7 +43,7 @@ In the example below, we are taking the `Authorization` header from `www.example In the example below, we are redirecting from `www.example.org` to `www.example.com` by setting the URL and using a message variable to make sure we keep the page path. -1. Open the `Rules` tab. +1. Open the `HTTP Rules` tab. 2. Create or open a Rule. 3. Set a `Rule Name` and add other Whens and Thens as needed. 4. Add When -> `Event Direction` (if not already added). @@ -59,7 +59,7 @@ In the example below, we are redirecting from `www.example.org` to `www.example. In the example below, we tell the browser to allow any origin by overriding the `Access-Control-Allow-Origin` response header. -1. Open the `Rules` tab. +1. Open the `HTTP Rules` tab. 2. Create or open a Rule. 3. Set a `Rule Name` and add other Whens and Thens as needed. 4. Add When -> `Event Direction` (if not already added). @@ -78,7 +78,7 @@ In the example below, we tell the browser to allow any origin by overriding the 2. Add a new Variable. 3. Set a `Variable Name`. We will use `mockResponse` for this example. 4. Paste the full response text (including headers and body) in `Variable Text`. -4. Open the `Rules` tab. +4. Open the `HTTP Rules` tab. 5. Create or open a Rule. 6. Set a `Rule Name` and add other Whens and Thens as needed. 7. Add When -> `Event Direction` (if not already added). @@ -93,11 +93,11 @@ In the example below, we tell the browser to allow any origin by overriding the **Drop a request so that it is not sent to an external server:** -The example of drop requests below works on all supported tools: Proxy, Repeater, Intruder, Scanner, Spider, Target, Extender (other extensions). +The example of drop requests below works on all supported tools: Proxy, Repeater, Intruder, Scanner, Target, Extender (other extensions). 1. Open the `Settings` tab. 2. Ensure the tool is selected under `Capture Traffic From:` -3. Open the `Rules` tab. +3. Open the `HTTP Rules` tab. 4. Create or open a Rule. 5. Set a `Rule Name` and add other Whens and Thens as needed. 6. Add When -> `Event Direction` (if not already added). diff --git a/docs/MessageValues.md b/docs/MessageValues.md index bc3a137..d66d936 100644 --- a/docs/MessageValues.md +++ b/docs/MessageValues.md @@ -1,5 +1,9 @@ # Message Values +Message values are values that are extracted from components of the HTTP message, WebSocket message, or connection details associated with an event that is being processed by Rules. + +Note: HTTP message values that are accessible by WebSocket Rule operations refer to components of the originating ws:// or wss:// request that triggered the establishment of the WebSocket connection. + * auto-gen TOC: {:toc} @@ -7,6 +11,8 @@ Key: SourceAddress +Rule Availability: HTTP + Example: `127.0.0.1` ## Destination Address @@ -15,12 +21,16 @@ Host name without port. Key: DestinationAddress +Rule Availability: HTTP, WebSocket + Example: `www.example.com` ## Destination Port Key: DestinationPort +Rule Availability: HTTP, WebSocket + Example: `80` ## Protocol @@ -29,16 +39,28 @@ Example: `80` Key: HttpProtocol +Rule Availability: HTTP, WebSocket + ## URL Key: URL +Rule Availability: HTTP, WebSocket + Example: `http://www.example.com/index.html?query=test` +## WebSocket Message + +Key: WebSocketMessage + +Rule Availability: WebSocket + ## Request Message Key: HttpRequestMessage +Rule Availability: HTTP, WebSocket + Example: ``` GET / HTTP/1.1 @@ -57,42 +79,56 @@ Cache-Control: no-cache Key: HttpRequestStatusLine +Rule Availability: HTTP, WebSocket + Example: `GET /path/to/page/index.html?claim=reset&type=plain HTTP/1.1` ## Request Method Key: HttpRequestMethod +Rule Availability: HTTP, WebSocket + Example: `GET` ## Request URI Key: HttpRequestUri +Rule Availability: HTTP, WebSocket + Example: `/path/to/page/index.html?claim=reset&type=plain` ## Request URI Path Key: HttpRequestUriPath +Rule Availability: HTTP, WebSocket + Example: `/path/to/page/index.html` from `/path/to/page/index.html?claim=reset&type=plain` ## Request URI Query Parameters Key: HttpRequestUriQueryParameters +Rule Availability: HTTP, WebSocket + Example: `claim=reset&type=plain` from `/path/to/page/index.html?claim=reset&type=plain` ## Request URI Query Parameter Key: HttpRequestUriQueryParameter +Rule Availability: HTTP, WebSocket + Example: Returns `plain` using identifier `type` given the request URI `/path/to/page/index.html?claim=reset&type=plain` ## Request Headers Key: HttpRequestHeaders +Rule Availability: HTTP, WebSocket + Example: ``` Host: www.example.com @@ -111,6 +147,8 @@ Cache-Control: no-cache Key: HttpRequestHeader +Rule Availability: HTTP, WebSocket + Example: Based request header `Accept-Encoding: gzip, deflate`, this returns `gzip, deflate` using identifier `Accept-Encoding` Example: `gzip, deflate` at identifier `Accept-Encoding` @@ -119,16 +157,22 @@ Example: `gzip, deflate` at identifier `Accept-Encoding` Key: HttpRequestCookie +Rule Availability: HTTP, WebSocket + Example: For cookie header `Cookie: AID=2Zy8`, this returns `2Zy8` using identifier `AID` ## Request Body Key: HttpRequestBody +Rule Availability: HTTP, WebSocket + ## Response Message Key: HttpResponseMessage +Rule Availability: HTTP + Example: ``` HTTP/1.1 404 Not Found @@ -150,23 +194,33 @@ Connection: close Key: HttpResponseStatusLine +Rule Availability: HTTP + Example: `HTTP/1.1 404 Not Found` ## Response Status Code Key: HttpResponseStatusCode +Rule Availability: HTTP + Example: `404` ## Response Status Message Key: HttpResponseStatusMessage +Rule Availability: HTTP + Example: `Not Found` ## Response Headers -Key: HttpResponseHeaders - Example: +Key: HttpResponseHeaders + +Rule Availability: HTTP + +Example: ``` HTTP/1.1 404 Not Found Accept-Ranges: bytes @@ -188,14 +242,20 @@ Connection: close Key: HttpResponseHeader +Rule Availability: HTTP + Example: Based response header `Cache-Control: max-age=604800`, this returns `max-age=604800` using identifier `Cache-Control` ## Response Cookie -Key: HttpResponseCookie +Key: HttpResponseCookie + +Rule Availability: HTTP Example: For cookie header `Set-Cookie: AID=2Zy8`, this returns `2Zy8` using identifier `AID` ## Response Body -Key: HttpResponseBody \ No newline at end of file +Key: HttpResponseBody + +Rule Availability: HTTP \ No newline at end of file diff --git a/docs/Readme.md b/docs/Readme.md index 3b9984e..f409d68 100644 --- a/docs/Readme.md +++ b/docs/Readme.md @@ -1,88 +1,94 @@ # Reshaper for Burp -Extension for Burp Suite to trigger actions and reshape HTTP request and response traffic using configurable rules +Extension for Burp Suite to trigger actions and reshape HTTP request/response and WebSocket traffic using configurable Rules -![Screenshot](https://user-images.githubusercontent.com/48854453/116795270-c797c100-aaa1-11eb-8353-580f7cf6e6d1.png) +![Screenshot](https://user-images.githubusercontent.com/48854453/206939994-3cf7beb7-61bb-4f12-8b7b-10239e4d0281.png) [Example Usage](https://synfron.github.io/ReshaperForBurp/Examples.html) ## Rules -Rules allow you to set actions to perform (called Thens) if HTTP messages/connections (event) received by Burp Suite meet certain criteria (called Whens). Rules are processed in order. +Rules allow you to set actions to perform (called Thens) if messages/connections (event) received by Burp Suite meet certain criteria (called Whens). Rules are processed in order. [More](https://synfron.github.io/ReshaperForBurp/Rules.html) ### Whens -Event Direction - If the HTTP message is a Request or Response +Content Type - If the HTTP request body is reported to match specified content types -Has Entity - If the HTTP event contains a certain entity +Event Direction - If the HTTP message is a Request or Response, or if the WebSocket message is directed toward the client or server -Matches Text - If a value (text, variable, or HTTP event entity) matches a value +From Tool - If the HTTP/WebSocket message is from a specific Burp tool -Content Type - If the HTTP request body is reported to match specified content types +Has Entity - If the HTTP/WebSocket event contains a certain message value entity -MIME Type - If the HTTP response body is reported to match specified MIME types +In Scope - If the URL is in the suite-wide scope -Proxy Name - If received by a certain Burp proxy listener +Matches Text - If a value (text, variable, or HTTP/WebSocket message value entity) matches a value -From Tool - If the HTTP message is from a specific Burp tool +Message Type - If the WebSocket message is text or binary -In Scope - If the URL is in the suite-wide scope +MIME Type - If the HTTP response body is reported to match specified MIME types + +Proxy Name - If received by a certain Burp proxy listener [More](https://synfron.github.io/ReshaperForBurp/Rules.html#whens) ### Thens -Break - Stop rules or then action processing - -Delay - Delay further processing/sending of the HTTP event +Break - Stop Rules or then action processing -Log - Log message to the Burp extension console - -Highlight - Highlight the request/response line in the HTTP history +Build HTTP Message - Build an HTTP request or response message and store the full text in a variable Comment - Add a comment to the request/response line in the HTTP history -Prompt - Get text via a prompt dialog +Delay - Delay further processing/sending of the HTTP/WebSocket event -Run Rules - Run a specific rule or all auto-run rules +Delete Value - Remove an HTTP message entity -Run Script - Execute a JavaScript script +Delete Variable - Delete a variable + +Drop - Have Burp drop the connection Evaluate - Perform operations on values -Set Event Direction - Change whether to send a request or to send a response at the end of processing +Highlight - Highlight the request/response line in the HTTP history -Set Encoding - Set the encoding used to read and write bytes of the HTTP request or response body +Intercept - Intercept the message in the Proxy interceptor -Set Value - Set the value of an HTTP event using another value (text, variable, or HTTP event entity) +Log - Log message to the Burp extension console -Delete Value - Remove an HTTP message entity +Parse HTTP Message - Extract values from an HTTP request or response message and store the values in variable -Set Variable - Set a variable using another value (text, variable, or HTTP event entity) +Prompt - Get text via a prompt dialog -Delete Variable - Delete a variable +Run Process - Execute a command in a separate process + +Run Rules - Run a specific Rule or all auto-run Rules + +Run Script - Execute a JavaScript script Save File - Save text to a file -Send To - Send data to other Burp tools or the system default browser +Set Encoding - Set the encoding used to read and write bytes of the HTTP request or response body, or WebSocket message -Run Process - Execute a command in a separate process +Set Event Direction - Change whether to send a request or to send a response at the end of processing -Build HTTP Message - Build an HTTP request or response message and store the full text in a variable +Set Value - Set the value of an HTTP/WebSocket event using another value (text, variable, or HTTP/WebSocket event entity) -Parse HTTP Message - Extract values from an HTTP request or response message and store the values in variable +Set Variable - Set a variable using another value (text, variable, or HTTP/WebSocket event entity) + +Send Message - Send a separate WebSocket message Send Request - Send a separate HTTP request -Drop - Have Burp drop the connection +Send To - Send data to other Burp tools or the system default browser [More](https://synfron.github.io/ReshaperForBurp/Rules.html#thens) ## Variables -Share values across different rules while processing the same event or all events. +Share values across different Rules while processing the same event or all events. [More](https://synfron.github.io/ReshaperForBurp/Variables.html) @@ -107,22 +113,22 @@ Share values across different rules while processing the same event or all event #### IntelliJ 1. Apply this [git patch](https://gist.github.com/ddwightx/6965732339bdf4cd022d550f40a9e99f) to the project to allow Reshaper to be debugged as a legacy extension in Burp Suite. -2. In Reshaper, using the Settings tab, export all rules and global variables to a JSON file to prevent data loss. +2. In Reshaper, using the Settings tab, export all Rules and global variables to a JSON file to prevent data loss. 3. In Extender, unload the Reshaper extension from Burp Suite if you already have the extension installed from the BApp Store or from a JAR. 4. Close Burp Suite. 5. Open the Reshaper project in IntelliJ. 6. Navigate to `java/synfron/reshaper/burp/ui/Window.java`. -7. Right click the file in the Project view and click `Run Window.main()` or `Run Window.main()`. +7. Right-click the file in the Project view and click `Run Window.main()` or `Run Window.main()`. 8. Burp Suite will open with Reshaper loaded as an legacy extension. #### CLI 1. Apply this [git patch](https://gist.github.com/ddwightx/6965732339bdf4cd022d550f40a9e99f) to the project to allow Reshaper to be debugged as a legacy extension in Burp Suite. -2. In Reshaper, using the Settings tab, export all rules and global variables to a JSON file to prevent data loss. +2. In Reshaper, using the Settings tab, export all Rules and global variables to a JSON file to prevent data loss. 3. In Extender, unload the Reshaper extension from Burp Suite if you already have the extension installed from the BApp Store or from a JAR. 4. Close Burp Suite. 5. In a CLI, execute `java -cp path/to/the/reshaper-for-burp/JAR/file.jar synfron.reshaper.burp.ui.Window`. -6. Burp Suite will open with Reshaper loaded as an legacy extension. +6. Burp Suite will open with Reshaper loaded as a legacy extension. ## Contributions diff --git a/docs/Rules.md b/docs/Rules.md index c4d393a..c92700e 100644 --- a/docs/Rules.md +++ b/docs/Rules.md @@ -1,43 +1,83 @@ # Rules -Rules allow you to set actions to perform (called Thens) if HTTP messages/connections (event) received by Burp Suite meet certain criteria (called Whens). Rules are processed in order. If the Rule is set to auto-run, the Rule will be run automatically when an HTTP event is received, otherwise it must be specifically triggered. Rules must be enabled to run at all. +Rules allow you to set actions to perform (called Thens) if a HTTP or WebSocket message (event) received by Burp Suite meet certain criteria (called Whens). Rules are processed in order. If the Rule is set to auto-run, the Rule will be run automatically when an HTTP or WebSocket event is received, otherwise it must be specifically triggered. Rules must be enabled to run at all. + +HTTP events are processed by Rules under the HTTP Rules tab. WebSocket events are processed by Rules under the WebSocket Rules tab. + +Note: HTTP message values that are accessible by WebSocket Rule operations refer to components of the originating ws:// or wss:// request that triggered the establishment of the WebSocket connection. * auto-gen TOC: {:toc} ## Whens -Check if an HTTP message meets certain criteria. Multiple Whens are checked in order and treated as AND conditions logically by default. If the relevant value does not match the constraints of the When (opposite if `Negate Result` is selected), unless the following When has specified to `Use OR Condition`, no further Whens are process for the current Rule and all Thens are skipped. +Check if an event message meets certain criteria. Multiple Whens are checked in order and treated as AND conditions logically by default. If the relevant value does not match the constraints of the When (opposite if `Negate Result` is selected), unless the following When has specified to `Use OR Condition`, no further Whens are process for the current Rule and all Thens are skipped. + +### Content Type + +If the HTTP request body is reported to match specified content types + +Availability: HTTP, WebSocket + +#### Fields + +Request Content Type - None, JSON, XML, URL Encoded, Multi-Part, AMF, and/or Unknown ### Event Direction -If the HTTP message is a Request or Response +If the HTTP message is a Request or Response, or if the WebSocket message is directed toward the client or server + +Availability: HTTP, WebSocket #### Fields -Event Direction - Request or Response +Event Direction - Request or Response for HTTP, Client or Server for WebSockets + +### From Tool + +If the HTTP/WebSocket message is from a specific Burp tool + +Availability: HTTP, WebSocket + +#### Fields + +Tool - Proxy, Repeater, Intruder, Target, Scanner, Extender, or Session ### Has Entity -If the HTTP event contains a certain entity +If the HTTP/WebSocket event contains a certain message value entity + +Availability: HTTP, WebSocket #### Fields -Message Value - The HTTP event entity to check +Message Value - The message value entity to check + +Identifier - The key of the property within the message value entity to check. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. + +### In Scope + +If the URL is in the suite-wide scope + +Availability: HTTP, WebSocket + +#### Fields -Identifier - The property of the HTTP entity to check. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. +URL - The URL to check or leave blank to use the current request's URL. Supports variable tags. ### Matches Text -If a value (text, variable, or HTTP event entity) matches a value +If a value (text, variable, or HTTP/WebSocket message value entity) matches a value + +Availability: HTTP, WebSocket #### Fields -Use Message Value - Match on a [Message Value](MessageValues.html) (HTTP event entity). Otherwise, use the specified text. +Use Message Value - Match on a [Message Value](MessageValues.html) (HTTP/WebSocket event entity). Otherwise, use the specified text. -Source Message Value - The HTTP event entity to check. Only available if `Use Message Value` is selected. +Source Message Value - The HTTP/WebSocket event entity to check. Only available if `Use Message Value` is selected. -Source Identifier - The property of the HTTP entity to check. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. +Source Identifier - The property of the HTTP/WebSocket entity to check. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. Source Identifier Placement - Placement of the value to get if there are multiple (i.e. First, Last). Only available for certain [Message Values](MessageValues.html) (e.g. request header). @@ -51,18 +91,24 @@ Match Type - Match the text using Equals, Contains, Begins With, Ends With, or R Match Text - The text to match the value against. Supports variable tags. -### Content Type +Ignore Case - If selected, use case-insensitive comparison. + +### Message Type -If the HTTP request body is reported to match specified content types. +If the WebSocket message type is text or binary + +Availability: WebSocket #### Fields -Request Content Type - None, JSON, XML, URL Encoded, Multi-Part, AMF, and/or Unknown +Message Type - Text or Binary ### MIME Type If the HTTP response body is reported to match specified MIME types. +Availability: HTTP + #### Fields Response MIME Type - HTML, Script, CSS, JSON, SVG, Other XML, Other Text, Image, Out Binary, and/or Unknown. @@ -71,112 +117,110 @@ Response MIME Type - HTML, Script, CSS, JSON, SVG, Other XML, Other Text, Image, If received by a certain Burp proxy listener -#### Fields - -Proxy Name - The Burp proxy listener interface (e.g. 127.0.0.1:8080) - -### From Tool - -If the HTTP message is from a specific Burp tool - -#### Fields - -Tool - Proxy, Repeater, Intruder, Target, Spider, Scanner, Extender, or Session - -### In Scope - -If the URL is in the suite-wide scope +Availability: HTTP #### Fields -URL - The URL to check or leave blank to use the current request's URL. Supports variable tags. +Proxy Name - The Burp proxy listener interface (e.g. 127.0.0.1:8080) ## Thens ### Break -Stop rules or then action processing +Stop Rules or then action processing + +Availability: HTTP, WebSocket #### Fields Break Type - If Skip Next Thens, skip running any further Thens of the Rule. If Skip Next Rules, skip running any further Thens and Rules for this event. -### Delay +### Build HTTP Message -Delay further processing/sending of the HTTP event +Build an HTTP request or response message and store the full text in a variable. The actual request or response message of the event is not changed. -#### Fields +Availability: HTTP, WebSocket -Delay (milliseconds) - The amount of time to delay further processing. Supports variable tags. +#### Fields -### Log +Starter HTTP Message - Text to use as the starting template for the HTTP message. Supports variable tags. -Log message to the Burp extension console +Message Value Setters - Set parts of the HTTP message. -#### Fields +Source Text - The text to set in the message. Supports variable tags. -Text - The text to log. Supports variable tags. +Destination Message Value - The HTTP message entity to set the value of. -### Highlight +Destination Identifier - The property of the HTTP message to set the value of. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. -Highlight the request/response line in the HTTP history +Destination Identifier Placement - Placement of the value to set if there are multiple (i.e. First, Last, All, Only - Keep One, New - Add additional). Only available for certain [Message Values](MessageValues.html) (e.g. request header). -#### Fields +Destination Variable Source - Global or Event scope. -Color - The color used to highlight the request/response line. +Destination Variable Name - The name of the variable to hold the built HTTP message. Supports variable tags. ### Comment Add a comment to the request/response line in the HTTP history +Availability: HTTP + #### Fields Text - The text of the comment. Supports variable tags. -### Prompt +### Delay + +Delay further processing/sending of the HTTP/WebSocket event -Get text via a prompt dialog. +Availability: HTTP, WebSocket #### Fields -Description - Description text to display in the prompt above the text entry field. Supports variable tags. +Delay (milliseconds) - The amount of time to delay further processing. Supports variable tags. -Starter Text - Initial text in the text entry field. Supports variable tags. +### Delete Value -Fail After (milliseconds) - Flag the request as failed after waiting the specified amount of time for the response. Only available if `Wait for Completion` is selected. Supports variable tags. +Remove an HTTP message entity -Break After Failure - Do not run any other Thens or Rules for this event if the request was flagged as failed. Only available if `Wait for Completion` is selected. +Availability: HTTP -Capture Variable Source - Global or Event scope. +#### Fields -Capture Variable Name - The name of variable to store the response message. Supports variable tags. +Message Value - The HTTP event entity to delete. -### Run Rules +Identifier - The property of the HTTP entity to delete. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. -Run a specific rule or all auto-run rules. +Identifier Placement - Placement of the value to delete if there are multiple. (i.e. First, Last, All) + +### Delete Variable + +Delete a variable + +Availability: HTTP, WebSocket #### Fields -Run Single - Run a specific Rule is selected. Otherwise, run all auto-run Rules. +Variable Source - Global or Event scope. -Run Name - The name of the Rule to run. Only available if `Run Single` is selected. +Variable Name - The name of the variable to delete. Supports variable tags. -### Run Script +### Drop -Execute a JavaScript script +Have Burp drop the connection -The engine supports up to partial ES6/ES2015. Scripts have access to certain Reshaper specific functions. See [Scripting Library](ScriptingLibrary.html) +Availability: HTTP, WebSocket #### Fields -Script - The text of the JavaScript script to run. - -Max Execution (secs) - Terminate long-running scripts after this time. +Drop Message - If selected, Burp will be told to drop the connection. ### Evaluate Perform operations on values +Availability: HTTP, WebSocket + #### Fields X - First value. Supports variable tags. @@ -185,120 +229,142 @@ Operation - `Add`, `Subtract`, `Multiply`, `Divide By`, `Increment`, `Decrement` Y - Second value. Only available for certain operations. Supports variable tags. -### Set Event Direction +### Highlight -Change whether to send a request or to send a response at the end of processing +Highlight the request/response line in the HTTP history -If the event direction is switched from request to response, no request is sent. Instead, whatever is set in the HTTP response message is sent. Switching from response to request is not functional. +Availability: HTTP #### Fields -Set Event Direction - Request or Response. +Color - The color used to highlight the request/response line. -### Set Encoding +### Intercept + +Intercept the message in the Proxy interceptor -Set the encoding used to read and write bytes of the HTTP request or response body. +Only relevant for Proxy tool captured events. + +Availability: HTTP, WebSocket #### Fields -Encoding - The charset/encoding of the file (e.g. uft-8). Supports variable tags. +Action - User Defined, Intercept, or Disable. +### Log -### Set Value +Log message to the Burp extension console -Set the value of an HTTP event using another value (text, variable, or HTTP event entity) +Availability: HTTP, WebSocket #### Fields -Use Message Value - Use [Message Value](MessageValues.html) (HTTP event entity) as the source value. Otherwise, use the specified text. +Text - The text to log. Supports variable tags. -Source Message Value - The HTTP event entity to get the source value from. Only available if `Use Message Value` is selected. +### Parse HTTP Message -Source Identifier - The property of the HTTP entity to get the source value from. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. +Extract values from an HTTP request or response message and store the values in variable. -Source Identifier Placement - Placement of the value to get if there are multiple (i.e. First, Last). Only available for certain [Message Values](MessageValues.html) (e.g. request header). +Availability: HTTP, WebSocket -Source Text - The text to use as the source value. Only available if `Use Message Value` is not selected. Supports variable tags. +#### Fields -Source Value Type - Declare that the value is Text, JSON (node), HTML (element), or Params (value). +HTTP Message - Text to use as the HTTP message. Supports variable tags. -Source Value Path - Specify a JSON path for JSON, a CSS selector for HTML, or a param name for Params to get a value from within the original value and then use this value instead. Only available if `Source Value Type` is JSON, HTML, or Params. Supports variable tags. +Message Value Getters - Get parts of the HTTP message. -Use Regex Replace - Use regex on the source value. +Source Text - The text to set in the message. Supports variable tags. -Regex Pattern - The Regex pattern to run on the source value. If there is a successful match, a Regex replace is performed on the value using `Regex Replacement Text`. Only available if `Use Regex Replace` is selected. Supports variable tags. +Source Message Value - The HTTP message entity to extract a value from. -Regex Pattern - The replacement value to use in the Regex replace. Only available if `Use Regex Replace` is selected. Supports variable tags. +Source Identifier - The property of the HTTP entity to extract a value from. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. -Destination Message Value - The HTTP event entity to set the value of. +Source Identifier Placement - Placement of the value to get if there are multiple (i.e. First, Last). Only available for certain [Message Values](MessageValues.html) (e.g. request header). -Destination Identifier - The property of the HTTP entity to set the value of. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. +Destination Variable Source - Global or Event scope. -Destination Identifier Placement - Placement of the value to set if there are multiple (i.e. First, Last, All, Only - Keep One, New - Add additional). Only available for certain [Message Values](MessageValues.html) (e.g. request header). +Destination Variable Name - The name of the variable to hold the built HTTP message value. Supports variable tags. -Destination Value Type - Declare that the value to set is Text, JSON (node), HTML (element), or Params (value). +### Prompt -Destination Value Path - Specify a JSON path for JSON, a CSS selector for HTML, or a param name for Params to get a value from within the original value and then use this value instead. Only available if `Destination Value Type` is JSON, HTML, or Params. Supports variable tags. +Get text via a prompt dialog +Availability: HTTP, WebSocket -### Delete Value +#### Fields -Remove an HTTP message entity +Description - Description text to display in the prompt above the text entry field. Supports variable tags. -#### Fields +Starter Text - Initial text in the text entry field. Supports variable tags. -Message Value - The HTTP event entity to delete. +Fail After (milliseconds) - Flag the request as failed after waiting the specified amount of time for the response. Only available if `Wait for Completion` is selected. Supports variable tags. -Identifier - The property of the HTTP entity to delete. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. +Break After Failure - Do not run any other Thens or Rules for this event if the request was flagged as failed. Only available if `Wait for Completion` is selected. -Identifier Placement - Placement of the value to delete if there are multiple. (i.e. First, Last, All) +Capture Variable Source - Global or Event scope. -### Set Variable +Capture Variable Name - The name of variable to store the response message. Supports variable tags. -Set a variable using another value (text, variable, or HTTP event entity) +### Run Process + +Execute a command in a separate process + +Availability: HTTP, WebSocket #### Fields -Use Message Value - Use [Message Value](MessageValues.html) (HTTP event entity) as the source value. Otherwise, use the specified text. +Command - Command to execute in a separate process. Supports variable tags. Example: `cmd.exe /c dir` -Source Message Value - The HTTP event entity to get the source value from. Only available if `Use Message Value` is selected. +Stdin - Value to send to standard input. Supports variable tags. -Source Identifier - The property of the HTTP entity to get the source value from. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. +Wait for Completion - Wait for the process to exit before continuing. -Source Identifier Placement - Placement of the value to get if there are multiple (i.e. First, Last). Only available for certain [Message Values](MessageValues.html) (e.g. request header). +Fail After (milliseconds) - Flag the process as failed after waiting the specified amount of time for the process to exit. Only available if `Wait for Completion` is selected. Supports variable tags. -Source Text - The text to use as the source value. Only available if `Use Message Value` is not selected. Supports variable tags. +Fail on Non-Zero Exit Code - Flag the process as failed if the process returned a non-zero exit code. Only available if `Wait for Completion` is selected. -Source Value Type - Declare that the value is Text, JSON (node), HTML (element), or Params (value). +Kill After Failure - Kill the process after a wait timeout. Only available if `Wait for Completion` is selected. -Source Value Path - Specify a JSON path for JSON, a CSS selector for HTML, or a param name for Params to get a value from within the original value and then use this value instead. Only available if `Source Value Type` is JSON, HTML, or Params. Supports variable tags. +Break After Failure - Do not run any other Thens or Rules for this event if the process was flagged as failed. Only available if `Wait for Completion` is selected. -Use Regex Replace - Use regex on the source value. +Capture Output - Capture standard out of the process. Only available if `Wait for Completion` is selected. -Regex Pattern - The Regex pattern to run on the source value. If there is a successful match, a Regex replace is performed on the value using `Regex Replacement Text`. Only available if `Use Regex Replace` is selected. Supports variable tags. +Capture After Failure - Capture standard out even if the process is flagged as failed. Only available if `Wait for Completion` and `Capture Output` is selected. -Regex Pattern - The replacement value to use in the Regex replace. Only available if `Use Regex Replace` is selected. Supports variable tags. +Capture Variable Source - Global or Event scope. -Destination Variable Source - Global or Event scope. +Capture Variable Name - The name of variable to store the captured output. Supports variable tags. -Destination Variable Name - The name of the variable to set. Supports variable tags. +### Run Rules -Destination Value Type - Declare that the value to set is Text, JSON (node), HTML (element), or Params (value). +Run a specific Rule or all auto-run Rules -Destination Value Path - Specify a JSON path for JSON, a CSS selector for HTML, or a param name for Params to get a value from within the original value and then use this value instead. Only available if `Destination Value Type` is JSON, HTML, or Params. Supports variable tags. +Availability: HTTP, WebSocket -### Delete Variable +#### Fields -Delete a variable +Run Single - Run a specific Rule is selected. Otherwise, run all auto-run Rules. + +Run Name - The name of the Rule to run. Only available if `Run Single` is selected. + +### Run Script + +Execute a JavaScript script + +Availability: HTTP, WebSocket + +The engine supports up to partial ES6/ES2015. Scripts have access to certain Reshaper specific functions. See [Scripting Library](ScriptingLibrary.html) #### Fields -Variable Source - Global or Event scope. +Script - The text of the JavaScript script to run. -Variable Name - The name of the variable to delete. Supports variable tags. +Max Execution (secs) - Terminate long-running scripts after this time. ### Save File -Save text to a file. +Save text to a file + +Availability: HTTP, WebSocket #### Fields @@ -310,143 +376,175 @@ Encoding - The charset/encoding of the file (e.g. uft-8). Supports variable tags File Exists Action - Action to do if the file already exist: None (Don't write), Overwrite, Append -### Send To - -Send data to other Burp tools or the system default browser +### Send Message -#### Fields +Send a separate WebSocket message -Send To - Comparer, Intruder, Repeater Spider, or Browser +Availability: WebSocket -Override Defaults - Select to be able to override values to send to the given Burp tool - -Host - Leave empty to use default value. Only available for Intruder and Repeater and if `Override Defaults` is selected. Supports variable tags. +#### Fields -Port - Leave empty to use default value. Only available for Intruder and Repeater and if `Override Defaults` is selected. Supports variable tags. +Event Direction - Send to Client or Server. Sending to the client is only allowed for WebSockets captured by the Proxy tool. -Protocol - HTTP or HTTPS. Leave empty to use default value. Only available for Intruder and Repeater and if `Override Defaults` is selected. Supports variable tags. +Message - The message to send. Supports variable tags. -Request - Full HTTP request text. Leave empty to use default value. Only available for Intruder and Repeater and if `Override Defaults` is selected. Supports variable tags. +### Send Request -Value - Value to compare. Leave empty to use default value. Only available for Comparer and if `Override Defaults` is selected. Supports variable tags. +Send a separate HTTP request -URL - Leave empty to use default value. Only available for if Spider or Browser, and `Override Defaults` is selected. Supports variable tags. +Availability: HTTP, WebSocket -### Run Process +#### Fields -Execute a command in a separate process +Request - The HTTP request message to send. Uses the value from the current event if left blank. Supports variable tags. -#### Fields +URL - The URL of the request. If this is set, it overrides the Host request header, the request message URI, protocol, address, and port. Supports variable tags. -Command - Command to execute in a separate process. Supports variable tags. Example: `cmd.exe /c dir` +Protocol - `http` or `https`. If this is set, it overrides the values from the URL (if set) or the current event. Supports variable tags. -Stdin - Value to send to standard input. Supports variable tags. +Address - Hostname without port. If this is set, it overrides the values from the URL (if set) or the current event. Example: `www.example.com`. Supports variable tags. -Wait for Completion - Wait for the process to exit before continuing. +Port - Example: `80`. If this is set, it overrides the values from the URL (if set) or the current event. Supports variable tags. -Fail After (milliseconds) - Flag the process as failed after waiting the specified amount of time for the process to exit. Only available if `Wait for Completion` is selected. Supports variable tags. +Wait for Completion - Wait for a response before continuing. -Fail on Non-Zero Exit Code - Flag the process as failed if the process returned a non-zero exit code. Only available if `Wait for Completion` is selected. +Fail After (milliseconds) - Flag the request as failed after waiting the specified amount of time for the response. Only available if `Wait for Completion` is selected. Supports variable tags. -Kill After Failure - Kill the process after a wait timeout. Only available if `Wait for Completion` is selected. +Fail on Error Status Code - Flag the request as failed if the response returned a with a 4xx or 5xx HTTP status code. Only available if `Wait for Completion` is selected. -Break After Failure - Do not run any other Thens or Rules for this event if the process was flagged as failed. Only available if `Wait for Completion` is selected. +Break After Failure - Do not run any other Thens or Rules for this event if the request was flagged as failed. Only available if `Wait for Completion` is selected. -Capture Output - Capture standard out of the process. Only available if `Wait for Completion` is selected. +Capture Output - Capture the HTTP response message. Only available if `Wait for Completion` is selected. -Capture After Failure - Capture standard out even if the process is flagged as failed. Only available if `Wait for Completion` and `Capture Output` is selected. +Capture After Failure - Capture the HTTP response message even if the request is flagged as failed. Only available if `Wait for Completion` and `Capture Output` is selected. Capture Variable Source - Global or Event scope. -Capture Variable Name - The name of variable to store the captured output. Supports variable tags. +Capture Variable Name - The name of variable to store the response message. Supports variable tags. -### Build HTTP Message +### Send To -Build an HTTP request or response message and store the full text in a variable. The actual request or response message of the event is not changed. +Send data to other Burp tools or the system default browser + +Availability: HTTP, WebSocket #### Fields -Starter HTTP Message - Text to use as the starting template for the HTTP message. Supports variable tags. +Send To - Comparer, Intruder, Repeater, or Browser -Message Value Setters - Set parts of the HTTP message. +Override Defaults - Select to be able to override values to send to the given Burp tool -Source Text - The text to set in the message. Supports variable tags. +Host - Leave empty to use default value. Only available for Intruder and Repeater and if `Override Defaults` is selected. Supports variable tags. -Destination Message Value - The HTTP message entity to set the value of. +Port - Leave empty to use default value. Only available for Intruder and Repeater and if `Override Defaults` is selected. Supports variable tags. -Destination Identifier - The property of the HTTP message to set the value of. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. +Protocol - HTTP or HTTPS. Leave empty to use default value. Only available for Intruder and Repeater and if `Override Defaults` is selected. Supports variable tags. -Destination Identifier Placement - Placement of the value to set if there are multiple (i.e. First, Last, All, Only - Keep One, New - Add additional). Only available for certain [Message Values](MessageValues.html) (e.g. request header). +Request - Full HTTP request text. Leave empty to use default value. Only available for Intruder and Repeater and if `Override Defaults` is selected. Supports variable tags. -Destination Variable Source - Global or Event scope. +Value - Value to compare. Leave empty to use default value. Only available for Comparer and if `Override Defaults` is selected. Supports variable tags. -Destination Variable Name - The name of the variable to hold the built HTTP message. Supports variable tags. +URL - Leave empty to use default value. Only available for Browser, and `Override Defaults` is selected. Supports variable tags. -### Parse HTTP Message +### Set Encoding -Extract values from an HTTP request or response message and store the values in variable. +Set the encoding used to read and write bytes of the HTTP request or response body, or WebSocket binary message + +Availability: HTTP, WebSocket #### Fields -HTTP Message - Text to use as the HTTP message. Supports variable tags. +Encoding - The charset/encoding of the file (e.g. uft-8). Supports variable tags. -Message Value Getters - Get parts of the HTTP message. +### Set Event Direction -Source Text - The text to set in the message. Supports variable tags. +Change whether to send a request or to send a response at the end of processing -Source Message Value - The HTTP message entity to extract a value from. +Availability: HTTP -Source Identifier - The property of the HTTP entity to extract a value from. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. +If the event direction is switched from request to response, no request is sent. Instead, whatever is set in the HTTP response message is sent. Switching from response to request is not functional. -Source Identifier Placement - Placement of the value to get if there are multiple (i.e. First, Last). Only available for certain [Message Values](MessageValues.html) (e.g. request header). +#### Fields -Destination Variable Source - Global or Event scope. +Set Event Direction - Request or Response. -Destination Variable Name - The name of the variable to hold the built HTTP message value. Supports variable tags. +### Set Value -### Send Request +Set the value of an HTTP/WebSocket event using another value (text, variable, or HTTP/WebSocket event entity) -Send a separate HTTP request. +Availability: HTTP, WebSocket #### Fields -Request - The HTTP request message to send. Uses the value from the current event if left blank. Supports variable tags. +Use Message Value - Use [Message Value](MessageValues.html) (HTTP/WebSocket event entity) as the source value. Otherwise, use the specified text. -URL - The URL of the request. If this is set, it overrides the Host request header, the request message URI, protocol, address, and port. Supports variable tags. +Source Message Value - The HTTP/WebSocket event entity to get the source value from. Only available if `Use Message Value` is selected. -Protocol - `http` or `https`. If this is set, it overrides the values from the URL (if set) or the current event. Supports variable tags. +Source Identifier - The property of the HTTP/WebSocket entity to get the source value from. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. -Address - Hostname without port. If this is set, it overrides the values from the URL (if set) or the current event. Example: `www.example.com`. Supports variable tags. +Source Identifier Placement - Placement of the value to get if there are multiple (i.e. First, Last). Only available for certain [Message Values](MessageValues.html) (e.g. request header). -Port - Example: `80`. If this is set, it overrides the values from the URL (if set) or the current event. Supports variable tags. +Source Text - The text to use as the source value. Only available if `Use Message Value` is not selected. Supports variable tags. -Wait for Completion - Wait for a response before continuing. +Source Value Type - Declare that the value is Text, JSON (node), HTML (element), or Params (value). -Fail After (milliseconds) - Flag the request as failed after waiting the specified amount of time for the response. Only available if `Wait for Completion` is selected. Supports variable tags. +Source Value Path - Specify a JSON path for JSON, a CSS selector for HTML, or a param name for Params to get a value from within the original value and then use this value instead. Only available if `Source Value Type` is JSON, HTML, or Params. Supports variable tags. -Fail on Error Status Code - Flag the request as failed if the response returned a with a 4xx or 5xx HTTP status code. Only available if `Wait for Completion` is selected. +Use Regex Replace - Use regex on the source value. -Break After Failure - Do not run any other Thens or Rules for this event if the request was flagged as failed. Only available if `Wait for Completion` is selected. +Regex Pattern - The Regex pattern to run on the source value. If there is a successful match, a Regex replace is performed on the value using `Regex Replacement Text`. Only available if `Use Regex Replace` is selected. Supports variable tags. -Capture Output - Capture the HTTP response message. Only available if `Wait for Completion` is selected. +Regex Pattern - The replacement value to use in the Regex replace. Only available if `Use Regex Replace` is selected. Supports variable tags. -Capture After Failure - Capture the HTTP response message even if the request is flagged as failed. Only available if `Wait for Completion` and `Capture Output` is selected. +Destination Message Value - The HTTP/WebSocket event entity to set the value of. -Capture Variable Source - Global or Event scope. +Destination Identifier - The property of the HTTP/WebSocket entity to set the value of. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. -Capture Variable Name - The name of variable to store the response message. Supports variable tags. +Destination Identifier Placement - Placement of the value to set if there are multiple (i.e. First, Last, All, Only - Keep One, New - Add additional). Only available for certain [Message Values](MessageValues.html) (e.g. request header). -### Drop +Destination Value Type - Declare that the value to set is Text, JSON (node), HTML (element), or Params (value). -Have Burp drop the connection +Destination Value Path - Specify a JSON path for JSON, a CSS selector for HTML, or a param name for Params to get a value from within the original value and then use this value instead. Only available if `Destination Value Type` is JSON, HTML, or Params. Supports variable tags. + +### Set Variable + +Set a variable using another value (text, variable, or HTTP/WebSocket event entity) + +Availability: HTTP, WebSocket #### Fields -Drop Message - If selected, Burp will be told to drop the connection. +Use Message Value - Use [Message Value](MessageValues.html) (HTTP/WebSocket event entity) as the source value. Otherwise, use the specified text. + +Source Message Value - The HTTP/WebSocket event entity to get the source value from. Only available if `Use Message Value` is selected. + +Source Identifier - The property of the HTTP/WebSocket entity to get the source value from. Only available for certain [Message Values](MessageValues.html) (e.g. request header). Supports variable tags. + +Source Identifier Placement - Placement of the value to get if there are multiple (i.e. First, Last). Only available for certain [Message Values](MessageValues.html) (e.g. request header). + +Source Text - The text to use as the source value. Only available if `Use Message Value` is not selected. Supports variable tags. + +Source Value Type - Declare that the value is Text, JSON (node), HTML (element), or Params (value). + +Source Value Path - Specify a JSON path for JSON, a CSS selector for HTML, or a param name for Params to get a value from within the original value and then use this value instead. Only available if `Source Value Type` is JSON, HTML, or Params. Supports variable tags. + +Use Regex Replace - Use regex on the source value. + +Regex Pattern - The Regex pattern to run on the source value. If there is a successful match, a Regex replace is performed on the value using `Regex Replacement Text`. Only available if `Use Regex Replace` is selected. Supports variable tags. + +Regex Pattern - The replacement value to use in the Regex replace. Only available if `Use Regex Replace` is selected. Supports variable tags. + +Destination Variable Source - Global or Event scope. + +Destination Variable Name - The name of the variable to set. Supports variable tags. + +Destination Value Type - Declare that the value to set is Text, JSON (node), HTML (element), or Params (value). + +Destination Value Path - Specify a JSON path for JSON, a CSS selector for HTML, or a param name for Params to get a value from within the original value and then use this value instead. Only available if `Destination Value Type` is JSON, HTML, or Params. Supports variable tags. ## Debugging -Rules can be debugged by enabling event diagnostics (*Settings > General > Enable Event Diagnostics*). This will log details about all rules that were run for each event (request or response) including the result of When constraint checks, and the values that were used in Whens and Thens. +Rules can be debugged by enabling event diagnostics (*Settings > General > Enable Event Diagnostics*) to debug all Rules or by right-clicking the specific Rules you want to debug in the Rules list and selecting `Toggle Debug Logging` in the context menu. This will log details about the actions the Rule(s) have taken for each event (request, response, or WebSocket message) processed, including the result of When constraint checks, and the values that were used in Whens and Thens. Example Diagnostic Output: ``` diff --git a/docs/ScriptingLibrary.md b/docs/ScriptingLibrary.md index 6a0e136..edeef04 100644 --- a/docs/ScriptingLibrary.md +++ b/docs/ScriptingLibrary.md @@ -71,6 +71,12 @@ BuildHttpMessage destinationVariableName: string } ``` +Comment +``` +{ + text: string +} +``` Delete Value ``` { @@ -97,10 +103,10 @@ Highlight color: "None" | "Red" | "Orange" | "Yellow" | "Green" | "Cyan" | "Blue" | "Pink" | "Magenta" | "Gray" } ``` -Comment +Intercept ``` { - text: string + interceptResponse: UserDefined | Disable | Intercept } ``` Log @@ -122,6 +128,13 @@ ParseHttpMessage }] } ``` +SendMessage +``` +{ + dataDirection: "Server" | "Client" + message: string +} +``` SendRequest ``` { @@ -142,7 +155,7 @@ SendRequest SendTo ``` { - sendTo: "Comparer" | "Intruder" | "Repeater" | "Spider" | "Browser" + sendTo: "Comparer" | "Intruder" | "Repeater" | "Browser" overrideDefaults: boolean host: string port: number @@ -213,6 +226,14 @@ Parameters: name - Variable name. +#### deleteSessionVariable(name) + +Delete an session variable. + +Parameters: + +name - Variable name. + #### getEventVariable(name) Get the value of an event variable. @@ -229,6 +250,14 @@ Parameters: name - Variable name. +#### getSessionVariable(name) + +Get the value of a session variable. + +Parameters: + +name - Variable name. + #### setEventVariable(name, value) Set the value of an event variable. @@ -248,3 +277,13 @@ Parameters: name - Variable name. value - The new value. + +#### setSessionVariable(name, value) + +Set the value of a session variable. + +Parameters: + +name - Variable name. + +value - The new value. diff --git a/docs/Variables.md b/docs/Variables.md index 60cdd90..4441ca9 100644 --- a/docs/Variables.md +++ b/docs/Variables.md @@ -2,11 +2,13 @@ ## Custom Variables -Custom variables allow the sharing of values between Rules and are scoped at the Global or Event level. Global and Event variables can be set by Thens or in the UI (Global variables only). Custom variables are only accessible within Reshaper and are readable by Whens and Thens. +Custom variables allow the sharing of values between Rules and are scoped at the Global, Session (WebSockets only), or Event level. Global, Session, and Event variables can be set by Thens or in the UI (Global variables only). Custom variables are only accessible within Reshaper and are readable by Whens and Thens. -Event variables are shared among rules running on a single HTTP event (either request or response). +Event variables are shared among Rules processing a single HTTP event (either request or response). -Global variables are shared among multiple HTTP events for as long at the extension is loaded or until the variables are deleted. Global variables can be set to be Persistent in the Global Variables tab of Reshaper. Persistent variables will be saved and reloaded between Reshaper sessions. +Global variables are shared among Rules across all events for as long as the extension is loaded or until the variables are deleted. Global variables can be set to be Persistent in the Global Variables tab of Reshaper. Persistent variables will be saved and reloaded between Reshaper sessions. + +Session variables are shared among Rules processing all WebSocket events within the same WebSocket connection. ## Accessor Variables @@ -14,6 +16,8 @@ Accessor variables provide access to utility functionality and data that is not Message variables provide access to event message values (e.g. Request URI). +Annotation variables process access to HTTP message annotation values (i.e. comments and highlight colors). HTTP Rules only. + File variables provide access to the contents of a text file. Special character variables provide access to special characters which typically require escape character sequences to use. (e.g. new lines, tabs, unicode characters) @@ -27,10 +31,14 @@ Variables can be read by Whens and Thens when a variable tag is specified in sup **Global Variable Tag (global, g):** `{{global:MyVariableName}}` +**Session Variable Tag (session, sn):** `{{session:MyVariableName}}` + For example, if Global variable named `firstName` has the value `John` and variable named `lastName` has the value `Smith`. A field with the value `{{global:firstName}}'s full name is {{global:firstName}} {{global:lastName}}` will be read as `John's full name is John Smith`. **Message Variable Tag (message, m):** `{{message:messageValueKey}}` or `{{message:messageValueKey:identifier}}` (e.g. `{{message:httprequesturi}}`, `{{message:httprequestheader:Host}}`). See [Message Values](MessageValues.html#) +**Annotation Variable Tag (annotation, a):** `{{annotation:comment}}` to get the current comment or `{{annotation:highlightcolor}}` to get the current highlight color of the line item in HTTP history for this event. + **File Variable Tag (file, f):** `{{file:encoding:filePath}}`. Example: `{{file:utf-8:~/Documents/file.txt}}` **Special Character Tag (special, s):** `{{s:specialCharacterSequences}}`. Examples: `{{s:n}}` (new line), `{{s:rn}}` (carriage return + new line), `{{s:u00A9}}` (Copyright symbol) diff --git a/docs/_config.yml b/docs/_config.yml index af9ec8a..e5a23d5 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,5 +1,5 @@ theme: jekyll-theme-cayman title: Reshaper for Burp -description: Trigger actions and reshape HTTP request and response traffic using configurable rules +description: Trigger actions and reshape HTTP request/response and WebSocket traffic using configurable rules kramdown: auto_ids: true diff --git a/gradlew b/gradlew index 744e882..1b6c787 100644 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/src/main/java/burp/BurpExtender.java b/src/main/java/burp/BurpExtender.java index 8172367..add2694 100644 --- a/src/main/java/burp/BurpExtender.java +++ b/src/main/java/burp/BurpExtender.java @@ -1,22 +1,33 @@ package burp; +import burp.api.montoya.BurpExtension; +import burp.api.montoya.MontoyaApi; +import burp.api.montoya.extension.ExtensionUnloadingHandler; +import burp.api.montoya.ui.editor.EditorOptions; +import burp.api.montoya.ui.editor.RawEditor; import lombok.Getter; -import synfron.reshaper.burp.core.Connector; +import synfron.reshaper.burp.core.HttpConnector; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.WebSocketConnector; import synfron.reshaper.burp.core.events.MessageEvent; +import synfron.reshaper.burp.core.rules.RulesRegistry; import synfron.reshaper.burp.core.settings.GeneralSettings; +import synfron.reshaper.burp.core.settings.SettingsManager; import synfron.reshaper.burp.core.utils.Log; import synfron.reshaper.burp.ui.components.ReshaperComponent; import synfron.reshaper.burp.ui.utils.ContextMenuHandler; import synfron.reshaper.burp.ui.utils.UiMessageHandler; -public class BurpExtender implements IBurpExtender { +public class BurpExtender implements BurpExtension, ExtensionUnloadingHandler { @Getter - private static IBurpExtenderCallbacks callbacks; + private static MontoyaApi api; @Getter - private final static Connector connector = new Connector(); + private final static HttpConnector httpConnector = new HttpConnector(); @Getter - private static ITextEditor logTextEditor; + private final static WebSocketConnector webSocketConnector = new WebSocketConnector(); + @Getter + private static RawEditor logTextEditor; @Getter private static final GeneralSettings generalSettings = new GeneralSettings(); @Getter @@ -25,20 +36,47 @@ public class BurpExtender implements IBurpExtender { private static final ContextMenuHandler contextMenuHandler = new ContextMenuHandler(); @Override - public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { - BurpExtender.callbacks = callbacks; - logTextEditor = callbacks.createTextEditor(); - logTextEditor.setEditable(false); - connector.init(); - - callbacks.addSuiteTab(new ReshaperComponent()); - callbacks.setExtensionName("Reshaper"); - callbacks.registerProxyListener(connector); - callbacks.registerHttpListener(connector); - callbacks.registerExtensionStateListener(connector); - callbacks.registerSessionHandlingAction(connector); - callbacks.registerContextMenuFactory(contextMenuHandler); - - Log.get().withMessage("Reshaper started").log(); + public void initialize(MontoyaApi api) { + try { + BurpExtender.api = api; + + logTextEditor = api.userInterface().createRawEditor(EditorOptions.READ_ONLY); + + SettingsManager.loadSettings(); + + httpConnector.init(); + + api.extension().setName("Reshaper"); + api.userInterface().registerSuiteTab("Reshaper", new ReshaperComponent()); + + api.proxy().registerRequestHandler(httpConnector); + api.proxy().registerResponseHandler(httpConnector); + api.proxy().registerWebSocketCreationHandler(webSocketConnector); + api.http().registerHttpHandler(httpConnector); + api.http().registerSessionHandlingAction(httpConnector); + api.extension().registerUnloadingHandler(this); + api.websockets().registerWebSocketCreationHandler(webSocketConnector); + api.userInterface().registerContextMenuItemsProvider(contextMenuHandler); + Log.get().withMessage("Reshaper started").log(); + + } catch (Exception e) { + Log.get().withMessage("Reshaper startup failed").withException(e).logErr(); + throw e; + } + } + + @Override + public void extensionUnloaded() { + httpConnector.unload(); + SettingsManager.saveSettings(); + Log.get().withMessage("Reshaper unloaded").log(); + } + + public static RulesRegistry getRulesRegistry(ProtocolType protocolType) { + return switch (protocolType) { + case Http -> httpConnector.getRulesEngine().getRulesRegistry(); + case WebSocket -> webSocketConnector.getRulesEngine().getRulesRegistry(); + case Any -> throw new IllegalArgumentException(protocolType + " not valid in this context"); + }; } } diff --git a/src/main/java/synfron/reshaper/burp/core/BurpTool.java b/src/main/java/synfron/reshaper/burp/core/BurpTool.java index 300e882..6b06ad7 100644 --- a/src/main/java/synfron/reshaper/burp/core/BurpTool.java +++ b/src/main/java/synfron/reshaper/burp/core/BurpTool.java @@ -1,28 +1,26 @@ package synfron.reshaper.burp.core; -import burp.IBurpExtenderCallbacks; -import lombok.Getter; - -import java.util.Arrays; +import burp.api.montoya.core.ToolType; public enum BurpTool { - Proxy(IBurpExtenderCallbacks.TOOL_PROXY), - Repeater(IBurpExtenderCallbacks.TOOL_REPEATER), - Intruder(IBurpExtenderCallbacks.TOOL_INTRUDER), - Target(IBurpExtenderCallbacks.TOOL_TARGET), - Spider(IBurpExtenderCallbacks.TOOL_SPIDER), - Scanner(IBurpExtenderCallbacks.TOOL_SCANNER), - Extender(IBurpExtenderCallbacks.TOOL_EXTENDER), - Session(null); - - @Getter - private final Integer id; - - BurpTool(Integer id) { - this.id = id; - } + Proxy, + Repeater, + Intruder, + Target, + Scanner, + Extender, + Session, + WebSockets; - public static BurpTool getById(int id) { - return Arrays.stream(values()).filter(tool -> tool.getId() == id).findFirst().orElse(null); + public static BurpTool from(ToolType toolType) { + return switch (toolType) { + case PROXY -> Proxy; + case TARGET -> Target; + case SCANNER -> Scanner; + case INTRUDER -> Intruder; + case REPEATER -> Repeater; + case EXTENSIONS -> Extender; + case SUITE, SEQUENCER, RECORDED_LOGIN_REPLAYER, COMPARER, DECODER, LOGGER -> null; + }; } } diff --git a/src/main/java/synfron/reshaper/burp/core/Connector.java b/src/main/java/synfron/reshaper/burp/core/Connector.java deleted file mode 100644 index a3dd6d5..0000000 --- a/src/main/java/synfron/reshaper/burp/core/Connector.java +++ /dev/null @@ -1,249 +0,0 @@ -package synfron.reshaper.burp.core; - -import burp.*; -import lombok.Getter; -import net.jodah.expiringmap.ExpiringMap; -import org.apache.commons.lang3.ArrayUtils; -import synfron.reshaper.burp.core.exceptions.WrappedException; -import synfron.reshaper.burp.core.messages.DataDirection; -import synfron.reshaper.burp.core.messages.EventInfo; -import synfron.reshaper.burp.core.messages.IEventInfo; -import synfron.reshaper.burp.core.rules.RulesEngine; -import synfron.reshaper.burp.core.settings.GeneralSettings; -import synfron.reshaper.burp.core.settings.SettingsManager; -import synfron.reshaper.burp.core.utils.Log; - -import java.io.*; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.InputMismatchException; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class Connector implements IProxyListener, IHttpListener, IExtensionStateListener, ISessionHandlingAction { - - private static final AtomicInteger lastMessageId = new AtomicInteger(1); - @Getter - private final RulesEngine rulesEngine = new RulesEngine(); - private ServerSocket serverSocket; - private final Map continuationMap = ExpiringMap.builder() - .expiration(30, TimeUnit.SECONDS).build(); - @Getter - private final SettingsManager settingsManager = new SettingsManager(); - private boolean activated = true; - private ExecutorService serverExecutor; - private final String dataDirectionWarning = "Sanity Check - Warning: The %s changed but the data direction is set to %s. Your changes may have no impact. Consider using 'When Data Direction' or 'Then Set Data Direction' to restrict or change the data direction."; - - public void init() { - activated = true; - settingsManager.loadSettings(); - createServer(); - } - - @Override - public void extensionUnloaded() { - activated = false; - settingsManager.saveSettings(); - closeServer(); - Log.get().withMessage("Reshaper unloaded").log(); - } - - private void closeServer() { - try { - if (serverExecutor != null) { - serverExecutor.shutdownNow(); - serverSocket.close(); - } - } catch (Exception ignored) {} - finally { - serverExecutor = null; - serverSocket = null; - } - } - - private void processServerConnection(Socket socket) { - serverExecutor.execute(() -> { - try { - BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); - bufferedReader.readLine(); - int reshaperId = getReshaperId(bufferedReader.readLine()); - IEventInfo eventInfo = continuationMap.remove(reshaperId); - if (eventInfo.isShouldDrop()) { - close(socket); - } - BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream()); - bufferedOutputStream.write(eventInfo.getHttpResponseMessage().getValue()); - bufferedOutputStream.flush(); - } catch (Exception e) { - if (activated) { - Log.get().withMessage("Event processing failed").withException(e).logErr(); - } - } finally { - close(socket); - } - }); - } - - private void createServer() { - try { - serverExecutor = Executors.newCachedThreadPool(); - serverSocket = new ServerSocket(0, 50, InetAddress.getLoopbackAddress()); - serverExecutor.execute(() -> { - while (activated) { - try { - Socket socket = serverSocket.accept(); - processServerConnection(socket); - } catch (Exception e) { - if (activated) { - Log.get().withMessage("Server accept new connection failed").withException(e).logErr(); - } - } - } - }); - } catch (IOException e) { - throw new WrappedException(e); - } - } - - private void close(Closeable closeable) { - try { - if (closeable != null) { - closeable.close(); - } - } catch (Exception ex) { - if (activated) { - Log.get().withMessage("Failed closing stream").withException(ex).logErr(); - } - } - } - - private IEventInfo asEventInfo(boolean messageIsRequest, IInterceptedProxyMessage message) { - IEventInfo eventInfo = new EventInfo(messageIsRequest ? DataDirection.Request : DataDirection.Response, message); - eventInfo.getDiagnostics().setEnabled(BurpExtender.getGeneralSettings().isEnableEventDiagnostics()); - return eventInfo; - } - - private IEventInfo asEventInfo(boolean messageIsRequest, BurpTool burpTool, IHttpRequestResponse requestResponse) { - IEventInfo eventInfo = new EventInfo(messageIsRequest ? DataDirection.Request : DataDirection.Response, burpTool, requestResponse); - eventInfo.getDiagnostics().setEnabled(BurpExtender.getGeneralSettings().isEnableEventDiagnostics()); - return eventInfo; - } - - private int getReshaperId(String header) { - if (!header.startsWith("Reshaper-ID:")) { - throw new InputMismatchException("No Reshaper-ID found"); - } - return Integer.parseInt(header.split(":", 2)[1].trim()); - } - - private void processEvent(boolean isRequest, IEventInfo eventInfo, IInterceptedProxyMessage interceptedMessage) { - int messageId = isRequest ? lastMessageId.getAndIncrement() : -1; - try { - rulesEngine.run(eventInfo); - if (eventInfo.isChanged()) { - sanityCheck(eventInfo); - IHttpRequestResponse messageInfo = eventInfo.getRequestResponse(); - if (eventInfo.getDataDirection() == DataDirection.Request) { - messageInfo.setRequest(eventInfo.getHttpRequestMessage().getValue()); - messageInfo.setHttpService(BurpExtender.getCallbacks().getHelpers().buildHttpService( - eventInfo.getDestinationAddress(), - eventInfo.getDestinationPort(), - eventInfo.getHttpProtocol().toLowerCase() - )); - if (eventInfo.isShouldDrop()) { - if (interceptedMessage != null) { - interceptedMessage.setInterceptAction(IInterceptedProxyMessage.ACTION_DROP); - } else { - sendToSelf(messageId, eventInfo, null); - } - } - } else if (isRequest && eventInfo.getDataDirection() == DataDirection.Response) { - sendToSelf(messageId, eventInfo, interceptedMessage); - } else { - messageInfo.setResponse(eventInfo.getHttpResponseMessage().getValue()); - } - } - } catch (Exception e) { - Log.get().withMessage("Critical Error").withException(e).logErr(); - } finally { - if (eventInfo.getDiagnostics().isEnabled()) { - Log.get().withMessage(eventInfo.getDiagnostics().getLogs()).logRaw(); - } - } - } - - private void sanityCheck(IEventInfo eventInfo) { - if (BurpExtender.getGeneralSettings().isEnableSanityCheckWarnings()) { - if (eventInfo.isRequestChanged() && eventInfo.getDataDirection() == DataDirection.Response) { - Log.get().withMessage(String.format(dataDirectionWarning, "request", "Response")).log(); - } - if (eventInfo.isResponseChanged() && eventInfo.getDataDirection() == DataDirection.Request) { - Log.get().withMessage(String.format(dataDirectionWarning, "response", "Request")).log(); - } - } - } - - private void sendToSelf(int messageId, IEventInfo eventInfo, IInterceptedProxyMessage interceptedMessage) { - IHttpRequestResponse messageInfo = eventInfo.getRequestResponse(); - messageInfo.setRequest(BurpExtender.getCallbacks().getHelpers().buildHttpMessage( - Stream.concat(Stream.of( - eventInfo.getHttpRequestMessage().getStatusLine().getValue(), - "Reshaper-ID: " + messageId - ), - eventInfo.getHttpRequestMessage().getHeaders().getValue().stream() - ).collect(Collectors.toList()), - eventInfo.getHttpRequestMessage().getBody().getValue() - )); - continuationMap.put(messageId, eventInfo); - messageInfo.setHttpService(BurpExtender.getCallbacks().getHelpers().buildHttpService( - serverSocket.getInetAddress().getHostAddress(), - serverSocket.getLocalPort(), - "http" - )); - if (interceptedMessage != null) { - interceptedMessage.setInterceptAction(IInterceptedProxyMessage.ACTION_DONT_INTERCEPT); - } - } - - @Override - public void processProxyMessage(boolean messageIsRequest, IInterceptedProxyMessage message) { - if (BurpExtender.getGeneralSettings().isCapture(BurpTool.Proxy)) { - IEventInfo eventInfo = asEventInfo(messageIsRequest, message); - processEvent(messageIsRequest, eventInfo, message); - } - } - - @Override - public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) { - if (toolFlag != BurpTool.Proxy.getId()) { - BurpTool burpTool = getBurpToolIfEnabled(toolFlag); - if (burpTool != null && burpTool != BurpTool.Proxy) { - IEventInfo eventInfo = asEventInfo(messageIsRequest, burpTool, messageInfo); - processEvent(messageIsRequest, eventInfo, null); - } - } - } - - private BurpTool getBurpToolIfEnabled(int toolFlag) { - BurpTool burpTool = BurpTool.getById(toolFlag); - return burpTool != null && BurpExtender.getGeneralSettings().isCapture(burpTool) ? burpTool : null; - } - - @Override - public String getActionName() { - return "Reshaper"; - } - - @Override - public void performAction(IHttpRequestResponse currentRequest, IHttpRequestResponse[] macroItems) { - boolean messageIsRequest = ArrayUtils.isEmpty(currentRequest.getResponse()); - IEventInfo eventInfo = asEventInfo(messageIsRequest, BurpTool.Session, currentRequest); - processEvent(messageIsRequest, eventInfo, null); - } -} diff --git a/src/main/java/synfron/reshaper/burp/core/HttpConnector.java b/src/main/java/synfron/reshaper/burp/core/HttpConnector.java new file mode 100644 index 0000000..185661d --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/HttpConnector.java @@ -0,0 +1,370 @@ +package synfron.reshaper.burp.core; + +import burp.BurpExtender; +import burp.api.montoya.core.Annotations; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.core.ToolSource; +import burp.api.montoya.core.ToolType; +import burp.api.montoya.http.HttpHandler; +import burp.api.montoya.http.HttpService; +import burp.api.montoya.http.RequestResult; +import burp.api.montoya.http.ResponseResult; +import burp.api.montoya.http.message.HttpRequestResponse; +import burp.api.montoya.http.message.requests.HttpRequest; +import burp.api.montoya.http.message.responses.HttpResponse; +import burp.api.montoya.http.sessions.SessionHandlingAction; +import burp.api.montoya.proxy.*; +import lombok.Getter; +import lombok.Setter; +import net.jodah.expiringmap.ExpiringMap; +import synfron.reshaper.burp.core.exceptions.WrappedException; +import synfron.reshaper.burp.core.messages.HttpDataDirection; +import synfron.reshaper.burp.core.messages.HttpEventInfo; +import synfron.reshaper.burp.core.messages.entities.http.HttpRequestMessage; +import synfron.reshaper.burp.core.rules.RulesEngine; +import synfron.reshaper.burp.core.utils.Log; + +import java.io.*; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.InputMismatchException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class HttpConnector implements + ProxyHttpRequestHandler, + ProxyHttpResponseHandler, + HttpHandler, + SessionHandlingAction +{ + + private static final AtomicInteger lastMessageId = new AtomicInteger(1); + @Getter + private final RulesEngine rulesEngine = new RulesEngine(); + private ServerSocket serverSocket; + private final Map continuationMap = ExpiringMap.builder() + .expiration(30, TimeUnit.SECONDS).build(); + private ExecutorService serverExecutor; + private final String dataDirectionWarning = "Sanity Check - Warning: The %s changed but the data direction is set to %s. Your changes may have no impact. Consider using 'When Data Direction' or 'Then Set Data Direction' to restrict or change the data direction."; + private final String interceptWarning = "Sanity Check - Warning: Cannot intercept unless the message is captured from the Proxy tool."; + private final String interceptAndDropWarning = "Sanity Check - Warning: Cannot both intercept and drop the same message."; + private boolean activated = true; + + public void init() { + activated = true; + createServer(); + } + + public void unload() { + activated = false; + closeServer(); + } + + private void closeServer() { + try { + if (serverExecutor != null) { + serverExecutor.shutdownNow(); + serverSocket.close(); + } + } catch (Exception ignored) {} + finally { + serverExecutor = null; + serverSocket = null; + } + } + + private void processServerConnection(Socket socket) { + serverExecutor.execute(() -> { + try { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); + bufferedReader.readLine(); + int reshaperId = getReshaperId(bufferedReader.readLine()); + HttpEventInfo eventInfo = continuationMap.get(reshaperId); + if (eventInfo.isShouldDrop()) { + continuationMap.remove(reshaperId); + close(socket); + } + BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream()); + bufferedOutputStream.write(eventInfo.getHttpResponseMessage().getValue()); + bufferedOutputStream.flush(); + } catch (Exception e) { + if (activated) { + Log.get().withMessage("Event processing failed").withException(e).logErr(); + } + } finally { + close(socket); + } + }); + } + + private void createServer() { + try { + serverExecutor = Executors.newCachedThreadPool(); + serverSocket = new ServerSocket(0, 50, InetAddress.getLoopbackAddress()); + serverExecutor.execute(() -> { + while (activated) { + try { + Socket socket = serverSocket.accept(); + processServerConnection(socket); + } catch (Exception e) { + if (activated) { + Log.get().withMessage("Server accept new connection failed").withException(e).logErr(); + } + } + } + }); + } catch (IOException e) { + throw new WrappedException(e); + } + } + + private void close(Closeable closeable) { + try { + if (closeable != null) { + closeable.close(); + } + } catch (Exception ex) { + if (activated) { + Log.get().withMessage("Failed closing stream").withException(ex).logErr(); + } + } + } + + private HttpEventInfo asEventInfo(boolean messageIsRequest, BurpTool burpTool, HttpRequest httpRequest, HttpResponse httpResponse, Annotations annotations) { + return asEventInfo( + messageIsRequest, + burpTool, + httpRequest, + httpResponse, + annotations, + null, + null + ); + } + + private HttpEventInfo asEventInfo(boolean messageIsRequest, BurpTool burpTool, HttpRequest httpRequest, HttpResponse httpResponse, Annotations annotations, String proxyName, InetAddress sourceIpAddress) { + if (!messageIsRequest && + httpRequest.httpService().port() == serverSocket.getLocalPort() && + httpRequest.httpService().host().equals(serverSocket.getInetAddress().getHostAddress()) + ) { + int reshaperId = Integer.parseInt(httpRequest.headers().get(1).value()); + HttpEventInfo requestEventInfo = continuationMap.remove(reshaperId); + httpRequest = requestEventInfo.getInitialHttpRequest(); + } + HttpEventInfo eventInfo = new HttpEventInfo( + messageIsRequest ? HttpDataDirection.Request : HttpDataDirection.Response, + burpTool, + httpRequest, + httpResponse, + annotations, + proxyName, + sourceIpAddress != null ? sourceIpAddress.getHostAddress() : "burp::" + ); + eventInfo.getDiagnostics().setEventEnabled(BurpExtender.getGeneralSettings().isEnableEventDiagnostics()); + return eventInfo; + } + + private int getReshaperId(String header) { + if (!header.startsWith("Reshaper-ID:")) { + throw new InputMismatchException("No Reshaper-ID found"); + } + return Integer.parseInt(header.split(":", 2)[1].trim()); + } + + private EventResult processEvent(boolean isRequest, HttpEventInfo eventInfo, boolean isIntercept) { + int messageId = isRequest ? lastMessageId.getAndIncrement() : -1; + EventResult eventResult = new EventResult(eventInfo); + try { + rulesEngine.run(eventInfo); + if (eventInfo.isChanged()) { + sanityCheck(eventInfo); + if (eventInfo.getDataDirection() == HttpDataDirection.Request) { + if (eventInfo.isShouldDrop()) { + if (isIntercept) { + eventResult.setInterceptResponse(InterceptResponse.Drop); + } else { + sendToSelf(messageId, eventInfo); + } + } else { + eventResult.setInterceptResponse(eventInfo.getDefaultInterceptResponse()); + } + } else if (isRequest && eventInfo.getDataDirection() == HttpDataDirection.Response) { + sendToSelf(messageId, eventInfo); + if (isIntercept) { + eventResult.setInterceptResponse(InterceptResponse.Disable); + } + } else if (!isRequest && isIntercept) { + eventResult.setInterceptResponse(eventInfo.getDefaultInterceptResponse()); + } + } + } catch (Exception e) { + Log.get().withMessage("Critical Error").withException(e).logErr(); + } finally { + if (eventInfo.getDiagnostics().hasLogs()) { + Log.get().withMessage(eventInfo.getDiagnostics().getLogs()).logRaw(); + } + } + return eventResult; + } + + private void sanityCheck(HttpEventInfo eventInfo) { + if (BurpExtender.getGeneralSettings().isEnableSanityCheckWarnings()) { + if (eventInfo.isRequestChanged() && eventInfo.getDataDirection() == HttpDataDirection.Response) { + Log.get().withMessage(String.format(dataDirectionWarning, "request", "Response")).log(); + } + if (eventInfo.isResponseChanged() && eventInfo.getDataDirection() == HttpDataDirection.Request) { + Log.get().withMessage(String.format(dataDirectionWarning, "response", "Request")).log(); + } + if (eventInfo.getDefaultInterceptResponse() == InterceptResponse.Intercept) { + if (eventInfo.isShouldDrop()) { + Log.get().withMessage(interceptAndDropWarning).log(); + } + if (eventInfo.getBurpTool() != BurpTool.Proxy) { + Log.get().withMessage(interceptWarning).log(); + } + } + } + } + + private void sendToSelf(int messageId, HttpEventInfo eventInfo) { + HttpRequestMessage requestMessage = eventInfo.getHttpRequestMessage(); + List headers = new ArrayList<>(); + headers.add(requestMessage.getStatusLine().getValue()); + headers.add(String.format("%s: %s", "Reshaper-ID", messageId)); + headers.addAll(requestMessage.getHeaders().getValue()); + HttpRequest httpRequest = HttpRequest.httpRequest( + HttpService.httpService( + serverSocket.getInetAddress().getHostAddress(), + serverSocket.getLocalPort(), + false + ), + headers, + ByteArray.byteArray(requestMessage.getBody().getValue()) + ); + continuationMap.put(messageId, eventInfo); + eventInfo.setHttpRequestOverride(httpRequest); + } + + private BurpTool getBurpToolIfEnabled(ToolType toolType) { + BurpTool burpTool = BurpTool.from(toolType); + return burpTool != null && BurpExtender.getGeneralSettings().isCapture(burpTool) ? burpTool : null; + } + + @Override + public RequestResult handleHttpRequest(HttpRequest request, Annotations annotations, ToolSource toolSource) { + if (!toolSource.isFromTool(ToolType.PROXY)) { + BurpTool burpTool = getBurpToolIfEnabled(toolSource.toolType()); + if (burpTool != null && burpTool != BurpTool.Proxy) { + HttpEventInfo eventInfo = asEventInfo(true, burpTool, request, null, annotations); + processEvent(true, eventInfo, false); + return RequestResult.requestResult(eventInfo.asHttpRequest(), eventInfo.getAnnotations()); + } + } + return RequestResult.requestResult(request, annotations); + } + + @Override + public ResponseResult handleHttpResponse(HttpResponse response, HttpRequest initiatingRequest, Annotations annotations, ToolSource toolSource) { + if (toolSource.toolType() != ToolType.PROXY) { + BurpTool burpTool = getBurpToolIfEnabled(toolSource.toolType()); + if (burpTool != null && burpTool != BurpTool.Proxy) { + HttpEventInfo eventInfo = asEventInfo(false, burpTool, initiatingRequest, response, annotations); + processEvent(false, eventInfo, false); + return ResponseResult.responseResult(eventInfo.asHttpResponse(), eventInfo.getAnnotations()); + } + } + return ResponseResult.responseResult(response, annotations); + } + + @Override + public String name() { + return "Reshaper"; + } + + @Override + public RequestResult handle(HttpRequest currentRequest, Annotations annotations, List macroRequestResponses) { + HttpEventInfo eventInfo = asEventInfo(true, BurpTool.Session, currentRequest, null, annotations); + processEvent(true, eventInfo, false); + return RequestResult.requestResult(eventInfo.asHttpRequest(), eventInfo.getAnnotations()); + } + + @Override + public RequestInitialInterceptResult handleReceivedRequest(InterceptedHttpRequest interceptedRequest, Annotations annotations) { + if (BurpExtender.getGeneralSettings().isCapture(BurpTool.Proxy)) { + HttpEventInfo eventInfo = asEventInfo(true, BurpTool.Proxy, interceptedRequest, null, annotations, interceptedRequest.listenerInterface(), interceptedRequest.sourceIpAddress()); + return processEvent(true, eventInfo, true).asRequestInterceptResult(); + } + else { + return RequestInitialInterceptResult.followUserRules(interceptedRequest, annotations); + } + } + + @Override + public RequestFinalInterceptResult handleRequestToIssue(InterceptedHttpRequest interceptedRequest, Annotations annotations) { + return RequestFinalInterceptResult.continueWith(interceptedRequest, annotations); + } + + @Override + public ResponseInitialInterceptResult handleReceivedResponse(InterceptedHttpResponse interceptedResponse, HttpRequest initiatingRequest, Annotations annotations) { + if (BurpExtender.getGeneralSettings().isCapture(BurpTool.Proxy)) { + HttpEventInfo eventInfo = asEventInfo(false, BurpTool.Proxy, initiatingRequest, interceptedResponse, annotations); + return processEvent(false, eventInfo, true).asResponseInterceptResult(); + } + else { + return ResponseInitialInterceptResult.followUserRules(interceptedResponse, annotations); + } + } + + @Override + public ResponseFinalInterceptResult handleResponseToReturn(InterceptedHttpResponse interceptedResponse, HttpRequest initiatingRequest, Annotations annotations) { + return ResponseFinalInterceptResult.continueWith(interceptedResponse, annotations); + } + + public static class EventResult { + private final HttpEventInfo eventInfo; + @Getter @Setter + private InterceptResponse interceptResponse; + + public EventResult(HttpEventInfo eventInfo) { + this.eventInfo = eventInfo; + interceptResponse = InterceptResponse.UserDefined; + } + + public HttpRequest getRequest() { + return eventInfo.asHttpRequest(); + } + + public HttpResponse getResponse() { + return eventInfo.asHttpResponse(); + } + + public Annotations getAnnotations() { + return eventInfo.getAnnotations(); + } + + public RequestInitialInterceptResult asRequestInterceptResult() { + return switch (interceptResponse) { + case UserDefined -> RequestInitialInterceptResult.followUserRules(getRequest(), getAnnotations()); + case Drop -> RequestInitialInterceptResult.drop(); + case Intercept -> RequestInitialInterceptResult.intercept(getRequest(), getAnnotations()); + case Disable -> RequestInitialInterceptResult.doNotIntercept(getRequest(), getAnnotations()); + }; + } + + public ResponseInitialInterceptResult asResponseInterceptResult() { + return switch (interceptResponse) { + case UserDefined -> ResponseInitialInterceptResult.followUserRules(getResponse(), getAnnotations()); + case Drop -> ResponseInitialInterceptResult.drop(); + case Intercept -> ResponseInitialInterceptResult.intercept(getResponse(), getAnnotations()); + case Disable -> ResponseInitialInterceptResult.doNotIntercept(getResponse(), getAnnotations()); + }; + } + } + +} diff --git a/src/main/java/synfron/reshaper/burp/core/InterceptResponse.java b/src/main/java/synfron/reshaper/burp/core/InterceptResponse.java new file mode 100644 index 0000000..69ddc92 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/InterceptResponse.java @@ -0,0 +1,22 @@ +package synfron.reshaper.burp.core; + +import lombok.Getter; + +public enum InterceptResponse { + UserDefined("Burp Defined"), + Drop("Drop"), + Disable("Disable"), + Intercept("Intercept"); + + @Getter + private final String name; + + InterceptResponse(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/ProtocolType.java b/src/main/java/synfron/reshaper/burp/core/ProtocolType.java new file mode 100644 index 0000000..774627e --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/ProtocolType.java @@ -0,0 +1,27 @@ +package synfron.reshaper.burp.core; + +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; + +public enum ProtocolType { + Any, + Http, + WebSocket; + + public static ProtocolType fromRuleOperationType(Class clazz) { + boolean isHttp = IHttpRuleOperation.class.isAssignableFrom(clazz); + boolean isWebSocket = IWebSocketRuleOperation.class.isAssignableFrom(clazz); + if (isHttp && isWebSocket) { + return Any; + } else if (isHttp) { + return Http; + } else if (isWebSocket) { + return WebSocket; + } + throw new IllegalArgumentException("No ProtocolType associated with class " + clazz); + } + + public boolean accepts(ProtocolType protocolType) { + return protocolType == ProtocolType.Any || this == ProtocolType.Any || this == protocolType; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/WebSocketConnector.java b/src/main/java/synfron/reshaper/burp/core/WebSocketConnector.java new file mode 100644 index 0000000..2d07d60 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/WebSocketConnector.java @@ -0,0 +1,211 @@ +package synfron.reshaper.burp.core; + +import burp.BurpExtender; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.core.ToolSource; +import burp.api.montoya.core.ToolType; +import burp.api.montoya.http.message.requests.HttpRequest; +import burp.api.montoya.internal.ObjectFactoryLocator; +import burp.api.montoya.proxy.*; +import burp.api.montoya.websocket.*; +import lombok.Getter; +import lombok.Setter; +import synfron.reshaper.burp.core.messages.WebSocketDataDirection; +import synfron.reshaper.burp.core.messages.WebSocketMessageType; +import synfron.reshaper.burp.core.messages.WebSocketEventInfo; +import synfron.reshaper.burp.core.rules.RulesEngine; +import synfron.reshaper.burp.core.utils.Log; +import synfron.reshaper.burp.core.vars.Variables; + +import java.util.function.BiConsumer; + +public class WebSocketConnector implements ProxyWebSocketCreationHandler, WebSocketCreationHandler { + @Getter + private final RulesEngine rulesEngine = new RulesEngine(); + + private BurpTool getBurpToolIfEnabled(ToolType toolType) { + BurpTool burpTool = BurpTool.from(toolType); + return burpTool != null && BurpExtender.getGeneralSettings().isCapture(burpTool) ? burpTool : null; + } + + @Override + public void handleWebSocketCreated(ProxyWebSocket proxyWebSocket, HttpRequest httpRequest) { + if (BurpExtender.getGeneralSettings().isCapture(BurpTool.Proxy) && BurpExtender.getGeneralSettings().isCapture(BurpTool.WebSockets)) { + proxyWebSocket.registerHandler(new WebSocketMessageConnector(BurpTool.Proxy, proxyWebSocket, httpRequest)); + } + } + + @Override + public void handleWebSocketCreated(WebSocket webSocket, HttpRequest httpRequest, ToolSource toolSource) { + if (!toolSource.isFromTool(ToolType.PROXY)) { + BurpTool burpTool = getBurpToolIfEnabled(toolSource.toolType()); + if (burpTool != null && burpTool != BurpTool.Proxy && BurpExtender.getGeneralSettings().isCapture(BurpTool.WebSockets)) { + webSocket.registerHandler(new WebSocketMessageConnector(BurpTool.Proxy, webSocket, httpRequest)); + } + } + } + + private class WebSocketMessageConnector implements ProxyWebSocketHandler, WebSocketHandler { + + private final BiConsumer messageSender; + private final HttpRequest httpRequest; + + private final BurpTool burpTool; + + private final Variables sessionVariables = new Variables(); + + public WebSocketMessageConnector(BurpTool burpTool, ProxyWebSocket webSocket, HttpRequest httpRequest) { + this.burpTool = burpTool; + this.messageSender = (WebSocketDataDirection dataDirection, String message) -> webSocket.sendTextMessage(message, dataDirection.toDirection()); + this.httpRequest = httpRequest; + } + + public WebSocketMessageConnector(BurpTool burpTool, WebSocket webSocket, HttpRequest httpRequest) { + this.burpTool = burpTool; + this.messageSender = (WebSocketDataDirection dataDirection, String message) -> { + if (dataDirection == WebSocketDataDirection.Client && burpTool != BurpTool.Proxy) { + throw new UnsupportedOperationException("Can only send client messages for Proxy WebSocket connections"); + } + webSocket.sendTextMessage(message); + }; + this.httpRequest = httpRequest; + } + + @Override + public ProxyWebSocketInitialInterceptTextMessage handleTextMessageReceived(String text, Direction direction) { + if (BurpExtender.getGeneralSettings().isCapture(BurpTool.WebSockets)) { + WebSocketEventInfo eventInfo = asEventInfo(WebSocketMessageType.Text, text, direction); + return processEvent(eventInfo).asTextProxyInterceptResult(); + } + return ObjectFactoryLocator.FACTORY.proxyWebSocketTextMessage(text, InitialInterceptAction.FOLLOW_USER_RULES); + } + + @Override + public WebSocketTextMessage handleTextMessage(String text, Direction direction) { + if (BurpExtender.getGeneralSettings().isCapture(BurpTool.WebSockets)) { + WebSocketEventInfo eventInfo = asEventInfo(WebSocketMessageType.Text, text, direction); + return processEvent(eventInfo).asTextInterceptResult(); + } + return WebSocketTextMessage.continueWithTextMessage(text); + } + + @Override + public ProxyWebSocketInitialInterceptBinaryMessage handleBinaryMessageReceived(ByteArray byteArray, Direction direction) { + if (BurpExtender.getGeneralSettings().isCapture(BurpTool.WebSockets)) { + WebSocketEventInfo eventInfo = asEventInfo(WebSocketMessageType.Binary, byteArray.getBytes(), direction); + return processEvent(eventInfo).asBinaryProxyInterceptResult(); + } + return ObjectFactoryLocator.FACTORY.proxyWebSocketBinaryMessage(byteArray, InitialInterceptAction.FOLLOW_USER_RULES); + } + + @Override + public WebSocketBinaryMessage handleBinaryMessage(ByteArray byteArray, Direction direction) { + if (BurpExtender.getGeneralSettings().isCapture(BurpTool.WebSockets)) { + WebSocketEventInfo eventInfo = asEventInfo(WebSocketMessageType.Binary, byteArray.getBytes(), direction); + return processEvent(eventInfo).asBinaryInterceptResult(); + } + return WebSocketBinaryMessage.continueWithBinaryMessage(byteArray); + } + + private WebSocketEventInfo asEventInfo(WebSocketMessageType messageType, T data, Direction direction) { + WebSocketEventInfo eventInfo = new WebSocketEventInfo<>( + messageType, + sessionVariables, + WebSocketDataDirection.from(direction), + burpTool, + messageSender, + httpRequest, + data + ); + eventInfo.getDiagnostics().setEventEnabled(BurpExtender.getGeneralSettings().isEnableEventDiagnostics()); + return eventInfo; + } + + private EventResult processEvent(WebSocketEventInfo eventInfo) { + EventResult eventResult = new EventResult<>(eventInfo); + try { + rulesEngine.run(eventInfo); + if (eventInfo.isChanged()) { + if (eventInfo.isShouldDrop()) { + eventResult.setInterceptResponse(InterceptResponse.Drop); + } else { + eventResult.setInterceptResponse(eventInfo.getDefaultInterceptResponse()); + } + } + } catch (Exception e) { + Log.get().withMessage("Critical Error").withException(e).logErr(); + } finally { + if (eventInfo.getDiagnostics().hasLogs()) { + Log.get().withMessage(eventInfo.getDiagnostics().getLogs()).logRaw(); + } + } + return eventResult; + } + + @Override + public ProxyWebSocketFinalInterceptTextMessage handleTextMessageToBeIssued(String text, Direction direction) { + return ProxyWebSocketFinalInterceptTextMessage.continueWithTextMessage(text); + } + + @Override + public ProxyWebSocketFinalInterceptBinaryMessage handleBinaryMessageToBeIssued(ByteArray byteArray, Direction direction) { + return ProxyWebSocketFinalInterceptBinaryMessage.continueWithBinaryMessage(byteArray); + } + + @Override + public void onClose() { + ProxyWebSocketHandler.super.onClose(); + } + } + + public static class EventResult { + private final WebSocketEventInfo eventInfo; + @Getter @Setter + private InterceptResponse interceptResponse; + + public EventResult(WebSocketEventInfo eventInfo) { + this.eventInfo = eventInfo; + interceptResponse = InterceptResponse.UserDefined; + } + + public T getData() { + return eventInfo.getData(); + } + + public ProxyWebSocketInitialInterceptTextMessage asTextProxyInterceptResult() { + return switch (interceptResponse) { + case UserDefined -> + ObjectFactoryLocator.FACTORY.proxyWebSocketTextMessage((String) eventInfo.getData(), InitialInterceptAction.FOLLOW_USER_RULES); + case Disable -> ProxyWebSocketInitialInterceptTextMessage.doNotInterceptTextMessage((String) eventInfo.getData()); + case Drop -> ProxyWebSocketInitialInterceptTextMessage.dropTextMessage(); + case Intercept -> ProxyWebSocketInitialInterceptTextMessage.interceptTextMessage((String) eventInfo.getData()); + }; + } + + public WebSocketTextMessage asTextInterceptResult() { + return switch (interceptResponse) { + case UserDefined, Disable, Intercept -> + WebSocketTextMessage.continueWithTextMessage((String)getData()); + case Drop -> WebSocketTextMessage.dropTextMessage(); + }; + } + + public ProxyWebSocketInitialInterceptBinaryMessage asBinaryProxyInterceptResult() { + return switch (interceptResponse) { + case UserDefined -> + ObjectFactoryLocator.FACTORY.proxyWebSocketBinaryMessage(ByteArray.byteArray((byte[]) eventInfo.getData()), InitialInterceptAction.FOLLOW_USER_RULES); + case Disable -> ProxyWebSocketInitialInterceptBinaryMessage.doNotInterceptBinaryMessage(ByteArray.byteArray((byte[]) eventInfo.getData())); + case Drop -> ProxyWebSocketInitialInterceptBinaryMessage.dropBinaryMessage(); + case Intercept -> ProxyWebSocketInitialInterceptBinaryMessage.interceptBinaryMessage(ByteArray.byteArray((byte[]) eventInfo.getData())); + }; + } + + public WebSocketBinaryMessage asBinaryInterceptResult() { + return switch (interceptResponse) { + case UserDefined, Disable, Intercept -> + WebSocketBinaryMessage.continueWithBinaryMessage(ByteArray.byteArray((byte[]) getData())); + case Drop -> WebSocketBinaryMessage.dropBinaryMessage(); + }; + } + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/messages/ContentType.java b/src/main/java/synfron/reshaper/burp/core/messages/ContentType.java index 3d7946f..0b2b01f 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/ContentType.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/ContentType.java @@ -3,7 +3,6 @@ import lombok.EqualsAndHashCode; import lombok.Getter; -import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -60,11 +59,16 @@ private int getId() { return ids.length == 1 ? ids[0] : Unknown.getId(); } - public static ContentType get(String name) { - return getValues().stream() - .filter(contentType -> contentType.getName().equalsIgnoreCase(name)) - .findFirst() - .orElse(null); + public static ContentType get(burp.api.montoya.http.ContentType contentType) { + return switch (contentType) { + case AMF -> Amf; + case XML -> Xml; + case JSON -> Json; + case NONE -> None; + case MULTIPART -> MultiPart; + case URL_ENCODED -> UrlEncoded; + case UNKNOWN -> Unknown; + }; } public static ContentType get(int id) { diff --git a/src/main/java/synfron/reshaper/burp/core/messages/Encoder.java b/src/main/java/synfron/reshaper/burp/core/messages/Encoder.java index c3957f3..37f9e20 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/Encoder.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/Encoder.java @@ -104,11 +104,11 @@ private String decode(byte[] data, Charset primaryEncoding) { } private byte[] defaultEncode(String text) { - return BurpExtender.getCallbacks().getHelpers().stringToBytes(StringUtils.defaultString(text)); + return BurpExtender.getApi().utilities().byteUtils().convertFromString(StringUtils.defaultString(text)); } private String defaultDecode(byte[] data) { - return BurpExtender.getCallbacks().getHelpers().bytesToString(ObjectUtils.defaultIfNull(data, new byte[0])); + return BurpExtender.getApi().utilities().byteUtils().convertToString(ObjectUtils.defaultIfNull(data, new byte[0])); } private String autoDetectDecode(byte[] data) { diff --git a/src/main/java/synfron/reshaper/burp/core/messages/EventInfo.java b/src/main/java/synfron/reshaper/burp/core/messages/EventInfo.java index e05b9e3..a25e64d 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/EventInfo.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/EventInfo.java @@ -1,171 +1,83 @@ package synfron.reshaper.burp.core.messages; import burp.BurpExtender; -import burp.IHttpRequestResponse; -import burp.IInterceptedProxyMessage; -import lombok.Data; +import burp.api.montoya.http.message.requests.HttpRequest; import lombok.Getter; import synfron.reshaper.burp.core.BurpTool; -import synfron.reshaper.burp.core.exceptions.WrappedException; -import synfron.reshaper.burp.core.messages.entities.HttpRequestMessage; -import synfron.reshaper.burp.core.messages.entities.HttpResponseMessage; +import synfron.reshaper.burp.core.InterceptResponse; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.entities.http.HttpRequestMessage; import synfron.reshaper.burp.core.rules.diagnostics.Diagnostics; import synfron.reshaper.burp.core.rules.diagnostics.IDiagnostics; -import synfron.reshaper.burp.core.utils.ObjectUtils; -import synfron.reshaper.burp.core.utils.SetItemPlacement; +import synfron.reshaper.burp.core.utils.UrlUtils; import synfron.reshaper.burp.core.vars.Variables; -import java.net.MalformedURLException; -import java.net.URL; - -public class EventInfo implements IEventInfo { - @Getter - private final IHttpRequestResponse requestResponse; - @Getter - private final BurpTool burpTool; - @Getter - private DataDirection dataDirection; +public abstract class EventInfo { @Getter - private final String proxyName; + protected final HttpRequest initialHttpRequest; @Getter - private final String sourceAddress; + protected final BurpTool burpTool; @Getter - private String destinationAddress; + protected String destinationAddress; @Getter - private Integer destinationPort; + protected Integer destinationPort; @Getter - private String httpProtocol; + protected String httpProtocol; @Getter - private boolean shouldDrop; + protected boolean shouldDrop; @Getter - private HttpRequestMessage httpRequestMessage; + protected InterceptResponse defaultInterceptResponse = InterceptResponse.UserDefined; @Getter - private HttpResponseMessage httpResponseMessage; + protected HttpRequestMessage httpRequestMessage; @Getter - private final Variables variables = new Variables(); + protected final Variables variables = new Variables(); @Getter - private final Encoder encoder = new Encoder(BurpExtender.getGeneralSettings().getDefaultEncoding()); - private boolean changed; + protected final Encoder encoder = new Encoder(BurpExtender.getGeneralSettings().getDefaultEncoding()); + protected boolean changed; @Getter - private final IDiagnostics diagnostics = new Diagnostics(); + protected final IDiagnostics diagnostics = new Diagnostics(); - public EventInfo(DataDirection dataDirection, IInterceptedProxyMessage proxyMessage) { - this.burpTool = BurpTool.Proxy; - this.dataDirection = dataDirection; - this.requestResponse = proxyMessage.getMessageInfo(); - httpRequestMessage = new HttpRequestMessage(requestResponse.getRequest(), encoder); - httpResponseMessage = new HttpResponseMessage(requestResponse.getResponse(), encoder); - proxyName = proxyMessage.getListenerInterface(); - httpProtocol = requestResponse.getHttpService().getProtocol(); - sourceAddress = proxyMessage.getClientIpAddress().getHostAddress(); - destinationPort = requestResponse.getHttpService().getPort(); - destinationAddress = requestResponse.getHttpService().getHost(); - } - - public EventInfo(DataDirection dataDirection, BurpTool burpTool, IHttpRequestResponse requestResponse) { + public EventInfo(BurpTool burpTool, HttpRequest httpRequest) { this.burpTool = burpTool; - this.dataDirection = dataDirection; - this.requestResponse = requestResponse; - httpRequestMessage = new HttpRequestMessage(requestResponse.getRequest(), encoder); - httpResponseMessage = new HttpResponseMessage(requestResponse.getResponse(), encoder); - httpProtocol = requestResponse.getHttpService().getProtocol(); - sourceAddress = "burp::"; - destinationPort = requestResponse.getHttpService().getPort(); - destinationAddress = requestResponse.getHttpService().getHost(); - proxyName = null; + this.initialHttpRequest = httpRequest; + httpRequestMessage = new HttpRequestMessage(httpRequest, encoder); + destinationPort = httpRequest.httpService().port(); + destinationAddress = httpRequest.httpService().host(); } - public EventInfo(IEventInfo sourceEventInfo) { + protected EventInfo(EventInfo sourceEventInfo) { this.burpTool = sourceEventInfo.getBurpTool(); - this.dataDirection = sourceEventInfo.getDataDirection(); - this.requestResponse = null; + this.initialHttpRequest = null; this.encoder.setEncoding(sourceEventInfo.getEncoder().getEncoding(), sourceEventInfo.getEncoder().isAutoSet()); httpRequestMessage = new HttpRequestMessage(sourceEventInfo.getHttpRequestMessage().getValue(), encoder); - httpResponseMessage = new HttpResponseMessage(sourceEventInfo.getHttpResponseMessage().getValue(), encoder); httpProtocol = sourceEventInfo.getHttpProtocol(); - sourceAddress = sourceEventInfo.getSourceAddress(); destinationPort = sourceEventInfo.getDestinationPort(); destinationAddress = sourceEventInfo.getDestinationAddress(); - proxyName = sourceEventInfo.getProxyName(); } - @Override - public void setDataDirection(DataDirection dataDirection) { - this.dataDirection = dataDirection; - changed = true; - } + public abstract ProtocolType getProtocolType(); - @Override - public void setHttpRequestMessage(byte[] request) { - httpRequestMessage = new HttpRequestMessage(request, encoder); - changed = true; - } - - @Override - public void setHttpResponseMessage(byte[] response) { - httpResponseMessage = new HttpResponseMessage(response, encoder); - changed = true; - } - - @Override - public void setDestinationAddress(String destinationAddress) { - this.destinationAddress = destinationAddress; - changed = true; - } - - @Override - public void setDestinationPort(int destinationPort) { - this.destinationPort = destinationPort; - changed = true; - } - - @Override - public void setHttpProtocol(String httpProtocol) { - this.httpProtocol = httpProtocol; - changed = true; - } - - @Override public void setShouldDrop(boolean shouldDrop) { this.shouldDrop = shouldDrop; changed = true; } - @Override - public void setUrl(String urlStr) { - try { - URL url = new URL(urlStr); - setHttpProtocol(url.getProtocol()); - setDestinationAddress(url.getHost()); - setDestinationPort(url.getPort() > 0 ? url.getPort() : url.getDefaultPort()); - getHttpRequestMessage().setUrl(url); - } catch (MalformedURLException e) { - throw new WrappedException(e); - } + public void setDefaultInterceptResponse(InterceptResponse defaultInterceptResponse) { + this.defaultInterceptResponse = defaultInterceptResponse; + changed = true; } - @Override public boolean isChanged() { return changed || - (httpRequestMessage != null && httpRequestMessage.isChanged()) || - (httpResponseMessage != null && httpResponseMessage.isChanged()); + (httpRequestMessage != null && httpRequestMessage.isChanged()); } - @Override - public boolean isRequestChanged() { - return httpRequestMessage != null && httpRequestMessage.isChanged(); - } - - @Override - public boolean isResponseChanged() { - return httpResponseMessage != null && httpResponseMessage.isChanged(); - } + public abstract boolean isSecure(); - @Override public String getUrl() { String url; try { - url = ObjectUtils.getUrl( + url = UrlUtils.getUrl( getHttpProtocol().toLowerCase(), getDestinationAddress(), getDestinationPort(), diff --git a/src/main/java/synfron/reshaper/burp/core/messages/DataDirection.java b/src/main/java/synfron/reshaper/burp/core/messages/HttpDataDirection.java similarity index 69% rename from src/main/java/synfron/reshaper/burp/core/messages/DataDirection.java rename to src/main/java/synfron/reshaper/burp/core/messages/HttpDataDirection.java index 8280454..d459840 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/DataDirection.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/HttpDataDirection.java @@ -1,6 +1,6 @@ package synfron.reshaper.burp.core.messages; -public enum DataDirection { +public enum HttpDataDirection { Request, Response } diff --git a/src/main/java/synfron/reshaper/burp/core/messages/HttpEventInfo.java b/src/main/java/synfron/reshaper/burp/core/messages/HttpEventInfo.java new file mode 100644 index 0000000..28ff1e7 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/messages/HttpEventInfo.java @@ -0,0 +1,143 @@ +package synfron.reshaper.burp.core.messages; + +import burp.api.montoya.core.Annotations; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.http.HttpService; +import burp.api.montoya.http.message.requests.HttpRequest; +import burp.api.montoya.http.message.responses.HttpResponse; +import lombok.Getter; +import lombok.Setter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.BurpTool; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.entities.http.HttpRequestMessage; +import synfron.reshaper.burp.core.messages.entities.http.HttpResponseMessage; +import synfron.reshaper.burp.core.utils.Url; + +public class HttpEventInfo extends EventInfo { + @Getter + private final HttpResponse initialHttpResponse; + @Getter @Setter + private Annotations annotations; + @Getter + private final HttpDataDirection initialDataDirection; + @Getter + private HttpDataDirection dataDirection; + @Getter + private HttpResponseMessage httpResponseMessage; + @Getter + protected final String proxyName; + @Getter + protected final String sourceAddress; + private HttpRequest httpRequestOverride; + + public HttpEventInfo(HttpDataDirection dataDirection, BurpTool burpTool, HttpRequest httpRequest, HttpResponse httpResponse, Annotations annotations, String proxyName, String sourceAddress) { + super(burpTool, httpRequest); + this.initialDataDirection = dataDirection; + this.dataDirection = dataDirection; + this.httpProtocol = httpRequest.httpService().secure() ? "https" : "http"; + this.initialHttpResponse = httpResponse; + this.annotations = annotations; + this.httpResponseMessage = new HttpResponseMessage(httpResponse, encoder); + this.sourceAddress = sourceAddress; + this.proxyName = proxyName; + } + + public HttpEventInfo(HttpDataDirection dataDirection, BurpTool burpTool, HttpRequest httpRequest, HttpResponse httpResponse, Annotations annotations) { + this(dataDirection, burpTool, httpRequest, httpResponse, annotations, null, "burp::"); + } + + public HttpEventInfo(EventInfo sourceRequestEventInfo) { + super(sourceRequestEventInfo); + this.dataDirection = HttpDataDirection.Request; + this.initialDataDirection = HttpDataDirection.Request; + this.initialHttpResponse = null; + this.annotations = null; + this.sourceAddress = "burp::"; + this.proxyName = null; + } + + @Override + public ProtocolType getProtocolType() { + return ProtocolType.Http; + } + + public void setDataDirection(HttpDataDirection dataDirection) { + this.dataDirection = dataDirection; + changed = true; + } + + public void setHttpRequestMessage(byte[] request) { + httpRequestMessage = new HttpRequestMessage(request, encoder); + changed = true; + } + + public void setHttpResponseMessage(byte[] response) { + httpResponseMessage = new HttpResponseMessage(response, encoder); + changed = true; + } + + public void setDestinationAddress(String destinationAddress) { + this.destinationAddress = destinationAddress; + changed = true; + } + + public void setDestinationPort(Integer destinationPort) { + this.destinationPort = destinationPort; + changed = true; + } + + public void setHttpProtocol(String httpProtocol) { + this.httpProtocol = httpProtocol; + changed = true; + } + + public void setUrl(String urlStr) { + Url url = new Url(urlStr); + setHttpProtocol(url.getProtocol()); + setDestinationAddress(url.getHost()); + setDestinationPort(url.getPort() > 0 ? url.getPort() : url.getDefaultPort()); + getHttpRequestMessage().setUrl(url); + } + + @Override + public boolean isChanged() { + return super.isChanged() || + (httpResponseMessage != null && httpResponseMessage.isChanged()); + } + + public boolean isRequestChanged() { + return httpRequestMessage != null && httpRequestMessage.isChanged(); + } + + public boolean isResponseChanged() { + return httpResponseMessage != null && httpResponseMessage.isChanged(); + } + + @Override + public boolean isSecure() { + return StringUtils.equalsIgnoreCase("https", httpProtocol); + } + + public HttpRequest asHttpRequest() { + return httpRequestOverride != null ? httpRequestOverride : (isChanged() || initialHttpRequest == null ? + HttpRequest.httpRequest(ByteArray.byteArray(httpRequestMessage.getValue())) + .withService(HttpService.httpService( + destinationAddress, + destinationPort, + isSecure() + )) : + initialHttpRequest); + } + + public void setHttpRequestOverride(HttpRequest httpRequest) { + this.httpRequestOverride = httpRequest; + } + + public HttpResponse asHttpResponse() { + return isChanged() || initialHttpResponse == null ? + HttpResponse.httpResponse(ByteArray.byteArray(httpResponseMessage.getValue())) : + initialHttpResponse; + } + +} diff --git a/src/main/java/synfron/reshaper/burp/core/messages/IEventInfo.java b/src/main/java/synfron/reshaper/burp/core/messages/IEventInfo.java deleted file mode 100644 index c9cac5d..0000000 --- a/src/main/java/synfron/reshaper/burp/core/messages/IEventInfo.java +++ /dev/null @@ -1,57 +0,0 @@ -package synfron.reshaper.burp.core.messages; - -import synfron.reshaper.burp.core.rules.diagnostics.IDiagnostics; - -public interface IEventInfo { - void setDataDirection(DataDirection dataDirection); - - void setHttpRequestMessage(byte[] request); - - void setHttpResponseMessage(byte[] response); - - void setDestinationAddress(String destinationAddress); - - void setDestinationPort(int destinationPort); - - void setHttpProtocol(String httpProtocol); - - void setShouldDrop(boolean shouldDrop); - - void setUrl(String urlStr); - - boolean isChanged(); - - boolean isRequestChanged(); - - boolean isResponseChanged(); - - String getUrl(); - - burp.IHttpRequestResponse getRequestResponse(); - - synfron.reshaper.burp.core.BurpTool getBurpTool(); - - DataDirection getDataDirection(); - - String getProxyName(); - - String getSourceAddress(); - - String getDestinationAddress(); - - Integer getDestinationPort(); - - String getHttpProtocol(); - - boolean isShouldDrop(); - - synfron.reshaper.burp.core.messages.entities.HttpRequestMessage getHttpRequestMessage(); - - synfron.reshaper.burp.core.messages.entities.HttpResponseMessage getHttpResponseMessage(); - - Encoder getEncoder(); - - synfron.reshaper.burp.core.vars.Variables getVariables(); - - IDiagnostics getDiagnostics(); -} diff --git a/src/main/java/synfron/reshaper/burp/core/messages/MessageAnnotation.java b/src/main/java/synfron/reshaper/burp/core/messages/MessageAnnotation.java new file mode 100644 index 0000000..c1c6a98 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/messages/MessageAnnotation.java @@ -0,0 +1,21 @@ +package synfron.reshaper.burp.core.messages; + +import lombok.Getter; + +public enum MessageAnnotation { + Comment("Comment"), + HighlightColor("Highlight Color"); + + @Getter + private final String name; + + MessageAnnotation(String name) { + this.name = name; + } + + + @Override + public String toString() { + return name; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/messages/MessageValue.java b/src/main/java/synfron/reshaper/burp/core/messages/MessageValue.java index b9fc711..8b0c06c 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/MessageValue.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/MessageValue.java @@ -1,61 +1,84 @@ package synfron.reshaper.burp.core.messages; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; public enum MessageValue { - SourceAddress("Source Address", null, true, false), - DestinationAddress("Destination Address", DataDirection.Request, true, false), - DestinationPort("Destination Port", DataDirection.Request, true, false), - HttpProtocol("Protocol", DataDirection.Request, true, false), - Url("URL", DataDirection.Request, true, false, true, false), - HttpRequestMessage("Request Message", DataDirection.Request, true, true, false, false), - HttpRequestStatusLine("Request Status Line", DataDirection.Request, false, false), - HttpRequestMethod("Request Method", DataDirection.Request, false, false), - HttpRequestUri("Request URI", DataDirection.Request, false, false), - HttpRequestUriPath("Request URI Path", DataDirection.Request, false, false), - HttpRequestUriQueryParameters("Request URI Query Parameters", DataDirection.Request, false, false), - HttpRequestUriQueryParameter("Request URI Query Parameter", DataDirection.Request, false, true), - HttpRequestHeaders("Request Headers", DataDirection.Request, false, false), - HttpRequestHeader("Request Header", DataDirection.Request, false, true), - HttpRequestCookie("Request Cookie", DataDirection.Request, false, true), - HttpRequestBody("Request Body", DataDirection.Request, false, false), - HttpResponseMessage("Response Message", DataDirection.Response, true, true, false, false), - HttpResponseStatusLine("Response Status Line", DataDirection.Response, false, false), - HttpResponseStatusCode("Response Status Code", DataDirection.Response, false, false), - HttpResponseStatusMessage("Response Status Message", DataDirection.Response, false, false), - HttpResponseHeaders("Response Headers", DataDirection.Response, false, false), - HttpResponseHeader("Response Header", DataDirection.Response, false, true), - HttpResponseCookie("Response Cookie", DataDirection.Response, false, true), - HttpResponseBody("Response Body", DataDirection.Response, false, false); + SourceAddress("HTTP Source Address", null, true, true, false, false, false, false, false), + DestinationAddress("HTTP Destination Address", HttpDataDirection.Request, true, true, true, true, false, false, false), + DestinationPort("HTTP Destination Port", HttpDataDirection.Request, true, true, true, true, false, false, false), + HttpProtocol("URL Protocol", HttpDataDirection.Request, true, true, true, true, false, false, false), + Url("URL", HttpDataDirection.Request, true, true, true, true, false, false, true, false, false), + WebSocketMessage("WebSocket Message", null, true, false, false, true, true, false, false), + HttpRequestMessage("Request Message", HttpDataDirection.Request, true, true, true, true, false, true, true, true, false), + HttpRequestStatusLine("Request Status Line", HttpDataDirection.Request, false, true, true, true, false, false, false), + HttpRequestMethod("Request Method", HttpDataDirection.Request, false, true, true, true, false, false, false), + HttpRequestUri("Request URI", HttpDataDirection.Request, false, true, true, true, false, false, false), + HttpRequestUriPath("Request URI Path", HttpDataDirection.Request, false, true, true, true, false, true, false), + HttpRequestUriQueryParameters("Request URI Query Parameters", HttpDataDirection.Request, false, true, true, true, false, true, false), + HttpRequestUriQueryParameter("Request URI Query Parameter", HttpDataDirection.Request, false, true, true, true, false, true, true), + HttpRequestHeaders("Request Headers", HttpDataDirection.Request, false, true, true, true, false, true, false), + HttpRequestHeader("Request Header", HttpDataDirection.Request, false, true, true, true, false, true, true), + HttpRequestCookie("Request Cookie", HttpDataDirection.Request, false, true, true, true, false, true, true), + HttpRequestBody("Request Body", HttpDataDirection.Request, false, true, true, true, false, true, false), + HttpResponseMessage("Response Message", HttpDataDirection.Response, true, true, true, false, false, true, true, true, false), + HttpResponseStatusLine("Response Status Line", HttpDataDirection.Response, false, true, true, false, false, false, false), + HttpResponseStatusCode("Response Status Code", HttpDataDirection.Response, false, true, true, false, false, false, false), + HttpResponseStatusMessage("Response Status Message", HttpDataDirection.Response, false, true, true, false, false, false, false), + HttpResponseHeaders("Response Headers", HttpDataDirection.Response, false, true, true, false, false, true, false), + HttpResponseHeader("Response Header", HttpDataDirection.Response, false, true, true, false, false, true, true), + HttpResponseCookie("Response Cookie", HttpDataDirection.Response, false, true, true, false, false, true, true), + HttpResponseBody("Response Body", HttpDataDirection.Response, false, true, true, false, false, true, false); @Getter private final String name; + @Getter - private final DataDirection dataDirection; + private final HttpDataDirection dataDirection; @Getter private final boolean topLevel; @Getter - private final boolean messageGettable; + private final boolean httpGettable; + @Getter + private final boolean httpSettable; + @Getter + private final boolean webSocketGettable; @Getter - private final boolean messageSettable; + private final boolean webSocketSettable; + @Getter + private final boolean innerLevelGettable; + @Getter + private final boolean innerLevelSettable; + + private final boolean deletable; @Getter private final boolean identifierRequired; - MessageValue(String name, DataDirection dataDirection, boolean topLevel, boolean identifierRequired) { + MessageValue(String name, HttpDataDirection dataDirection, boolean topLevel, boolean httpGettable, boolean httpSettable, boolean webSocketGettable, boolean webSocketSettable, boolean deletable, boolean identifierRequired) { this.name = name; this.dataDirection = dataDirection; this.topLevel = topLevel; - this.messageGettable = !topLevel; - this.messageSettable = !topLevel; + this.httpGettable = httpGettable; + this.httpSettable = httpSettable; + this.webSocketGettable = webSocketGettable; + this.webSocketSettable = webSocketSettable; + this.deletable = deletable; + this.innerLevelGettable = !topLevel; + this.innerLevelSettable = !topLevel; this.identifierRequired = identifierRequired; } - MessageValue(String name, DataDirection dataDirection, boolean topLevel, boolean messageGettable, boolean messageSettable, boolean identifierRequired) { + MessageValue(String name, HttpDataDirection dataDirection, boolean topLevel, boolean httpGettable, boolean httpSettable, boolean webSocketGettable, boolean webSocketSettable, boolean deletable, boolean innerLevelGettable, boolean innerLevelSettable, boolean identifierRequired) { this.name = name; this.dataDirection = dataDirection; this.topLevel = topLevel; - this.messageGettable = messageGettable; - this.messageSettable = messageSettable; + this.httpGettable = httpGettable; + this.httpSettable = httpSettable; + this.webSocketGettable = webSocketGettable; + this.webSocketSettable = webSocketSettable; + this.deletable = deletable; + this.innerLevelGettable = innerLevelGettable; + this.innerLevelSettable = innerLevelSettable; this.identifierRequired = identifierRequired; } @@ -63,4 +86,40 @@ public enum MessageValue { public String toString() { return name; } + + public boolean hasProtocolType(ProtocolType protocolType) { + return switch (protocolType) { + case Any -> httpGettable || httpSettable || webSocketGettable || webSocketSettable; + case Http -> httpGettable || httpSettable; + case WebSocket -> webSocketGettable || webSocketSettable; + }; + } + + public boolean isDeletable(ProtocolType protocolType) { + return isSettable(protocolType) && deletable; + } + + public boolean isInnerLevelGettable(ProtocolType protocolType) { + return isGettable(protocolType) && innerLevelGettable; + } + + public boolean isInnerLevelSettable(ProtocolType protocolType) { + return isSettable(protocolType) && innerLevelSettable; + } + + public boolean isGettable(ProtocolType protocolType) { + return switch (protocolType) { + case Any -> httpGettable || webSocketGettable; + case Http -> httpGettable; + case WebSocket -> webSocketGettable; + }; + } + + public boolean isSettable(ProtocolType protocolType) { + return switch (protocolType) { + case Any -> httpSettable || webSocketSettable; + case Http -> httpSettable; + case WebSocket -> webSocketSettable; + }; + } } diff --git a/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java b/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java index 09b86bd..4012f01 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/MessageValueHandler.java @@ -1,11 +1,10 @@ package synfron.reshaper.burp.core.messages; import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.messages.entities.HttpRequestMessage; -import synfron.reshaper.burp.core.messages.entities.HttpResponseMessage; +import synfron.reshaper.burp.core.messages.entities.http.HttpRequestMessage; +import synfron.reshaper.burp.core.messages.entities.http.HttpResponseMessage; import synfron.reshaper.burp.core.utils.GetItemPlacement; import synfron.reshaper.burp.core.utils.SetItemPlacement; -import synfron.reshaper.burp.core.utils.TextUtils; import synfron.reshaper.burp.core.vars.VariableString; import java.util.Collections; @@ -13,36 +12,37 @@ public class MessageValueHandler { - public static String getValue(IEventInfo eventInfo, MessageValue messageValue, VariableString identifier, GetItemPlacement itemPlacement) + public static String getValue(EventInfo eventInfo, MessageValue messageValue, VariableString identifier, GetItemPlacement itemPlacement) { String value; - if (!messageValue.isTopLevel() && messageValue.getDataDirection() == DataDirection.Request) { + if (!messageValue.isTopLevel() && messageValue.getDataDirection() == HttpDataDirection.Request) { value = getRequestValue(eventInfo, eventInfo.getHttpRequestMessage(), messageValue, identifier, itemPlacement); - } else if (!messageValue.isTopLevel() && messageValue.getDataDirection() == DataDirection.Response) { - value = getResponseValue(eventInfo, eventInfo.getHttpResponseMessage(), messageValue, identifier, itemPlacement); + } else if (!messageValue.isTopLevel() && messageValue.getDataDirection() == HttpDataDirection.Response) { + HttpEventInfo httpEventInfo = (HttpEventInfo)eventInfo; + value = getResponseValue(httpEventInfo, httpEventInfo.getHttpResponseMessage(), messageValue, identifier, itemPlacement); } else { value = switch (messageValue) { case HttpProtocol -> eventInfo.getHttpProtocol(); case Url -> eventInfo.getUrl(); - case SourceAddress -> eventInfo.getSourceAddress(); + case SourceAddress -> ((HttpEventInfo)eventInfo).getSourceAddress(); case DestinationPort -> Integer.toString(eventInfo.getDestinationPort()); case DestinationAddress -> eventInfo.getDestinationAddress(); case HttpRequestMessage -> eventInfo.getHttpRequestMessage().getText(); - case HttpResponseMessage -> eventInfo.getHttpResponseMessage().getText(); + case HttpResponseMessage -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getText(); + case WebSocketMessage -> ((WebSocketEventInfo)eventInfo).getText(); default -> throw new UnsupportedOperationException(String.format("Cannot get message value '%s'", messageValue)); }; } return StringUtils.defaultString(value); } - public static String getRequestValue(IEventInfo eventInfo, HttpRequestMessage requestMessage, MessageValue messageValue, VariableString identifier, GetItemPlacement itemPlacement) { + public static String getRequestValue(EventInfo eventInfo, HttpRequestMessage requestMessage, MessageValue messageValue, VariableString identifier, GetItemPlacement itemPlacement) { return switch (messageValue) { case HttpRequestHeaders -> requestMessage.getHeaders().getText(); case HttpRequestHeader -> requestMessage.getHeaders().getHeader(identifier.getText(eventInfo), itemPlacement); case HttpRequestBody -> requestMessage.getBody().getText(); case HttpRequestStatusLine -> requestMessage.getStatusLine().getValue(); case HttpRequestCookie -> requestMessage.getHeaders().getCookies().getCookie(identifier.getText(eventInfo), itemPlacement); - case HttpResponseCookie -> eventInfo.getHttpResponseMessage().getHeaders().getCookies().getCookie(identifier.getText(eventInfo), itemPlacement); case HttpRequestUri -> requestMessage.getStatusLine().getUrl().getValue(); case HttpRequestMessage -> requestMessage.getText(); case HttpRequestMethod -> requestMessage.getStatusLine().getMethod(); @@ -53,7 +53,7 @@ public static String getRequestValue(IEventInfo eventInfo, HttpRequestMessage re }; } - public static String getResponseValue(IEventInfo eventInfo, HttpResponseMessage responseMessage, MessageValue messageValue, VariableString identifier, GetItemPlacement itemPlacement) { + public static String getResponseValue(EventInfo eventInfo, HttpResponseMessage responseMessage, MessageValue messageValue, VariableString identifier, GetItemPlacement itemPlacement) { return switch (messageValue) { case HttpResponseHeaders -> responseMessage.getHeaders().getText(); case HttpResponseHeader -> responseMessage.getHeaders().getHeader(identifier.getText(eventInfo), itemPlacement); @@ -68,10 +68,26 @@ public static String getResponseValue(IEventInfo eventInfo, HttpResponseMessage } - public static void setValue(IEventInfo eventInfo, MessageValue messageValue, VariableString identifier, SetItemPlacement itemPlacement, String replacementText) { - if (!messageValue.isTopLevel() && messageValue.getDataDirection() == DataDirection.Request) { - setRequestValue(eventInfo, eventInfo.getHttpRequestMessage(), messageValue, identifier,itemPlacement, replacementText); - } else if (!messageValue.isTopLevel() && messageValue.getDataDirection() == DataDirection.Response) { + public static void setValue(EventInfo eventInfo, MessageValue messageValue, VariableString identifier, SetItemPlacement itemPlacement, String replacementText) { + if (eventInfo instanceof HttpEventInfo) { + HttpEventInfo httpEventInfo = (HttpEventInfo)eventInfo; + setValue(httpEventInfo, messageValue, identifier, itemPlacement, replacementText); + } else if (eventInfo instanceof WebSocketEventInfo) { + WebSocketEventInfo webSocketEventInfo = (WebSocketEventInfo)eventInfo; + setValue(webSocketEventInfo, messageValue, replacementText); + } + } + + private static void setValue(WebSocketEventInfo eventInfo, MessageValue messageValue, String replacementText) { + switch (messageValue) { + case WebSocketMessage -> eventInfo.setText(replacementText); + } + } + + private static void setValue(HttpEventInfo eventInfo, MessageValue messageValue, VariableString identifier, SetItemPlacement itemPlacement, String replacementText) { + if (!messageValue.isTopLevel() && messageValue.getDataDirection() == HttpDataDirection.Request) { + setRequestValue(eventInfo, eventInfo.getHttpRequestMessage(), messageValue, identifier, itemPlacement, replacementText); + } else if (!messageValue.isTopLevel() && messageValue.getDataDirection() == HttpDataDirection.Response) { setResponseValue(eventInfo, eventInfo.getHttpResponseMessage(), messageValue, identifier, itemPlacement, replacementText); } else { switch (messageValue) { @@ -86,7 +102,7 @@ public static void setValue(IEventInfo eventInfo, MessageValue messageValue, Var } } - public static void setRequestValue(IEventInfo eventInfo, HttpRequestMessage requestMessage, MessageValue messageValue, VariableString identifier, SetItemPlacement itemPlacement, String replacementText) { + public static void setRequestValue(EventInfo eventInfo, HttpRequestMessage requestMessage, MessageValue messageValue, VariableString identifier, SetItemPlacement itemPlacement, String replacementText) { switch (messageValue) { case HttpRequestHeaders -> requestMessage.setHeaders(StringUtils.defaultString(replacementText)); case HttpRequestHeader -> requestMessage.getHeaders().setHeader(identifier.getText(eventInfo), replacementText, itemPlacement); @@ -102,7 +118,7 @@ public static void setRequestValue(IEventInfo eventInfo, HttpRequestMessage requ } } - public static void setResponseValue(IEventInfo eventInfo, HttpResponseMessage responseMessage, MessageValue messageValue, VariableString identifier, SetItemPlacement itemPlacement, String replacementText) { + public static void setResponseValue(EventInfo eventInfo, HttpResponseMessage responseMessage, MessageValue messageValue, VariableString identifier, SetItemPlacement itemPlacement, String replacementText) { switch (messageValue) { case HttpResponseHeaders -> responseMessage.setHeaders(StringUtils.defaultString(replacementText)); case HttpResponseHeader -> responseMessage.getHeaders().setHeader(identifier.getText(eventInfo), replacementText, itemPlacement); @@ -114,12 +130,12 @@ public static void setResponseValue(IEventInfo eventInfo, HttpResponseMessage re } } - public static List getIdentifier(IEventInfo eventInfo, MessageValue messageValue) { + public static List getIdentifier(EventInfo eventInfo, MessageValue messageValue) { return switch (messageValue) { case HttpRequestHeader -> eventInfo.getHttpRequestMessage().getHeaders().getHeaderNames(); - case HttpResponseHeader -> eventInfo.getHttpResponseMessage().getHeaders().getHeaderNames(); + case HttpResponseHeader -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getHeaders().getHeaderNames(); case HttpRequestCookie -> eventInfo.getHttpRequestMessage().getHeaders().getCookies().getCookiesNames(); - case HttpResponseCookie -> eventInfo.getHttpResponseMessage().getHeaders().getCookies().getCookiesNames(); + case HttpResponseCookie -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getHeaders().getCookies().getCookiesNames(); case HttpRequestUriQueryParameter -> eventInfo.getHttpRequestMessage().getStatusLine().getUrl().getQueryParams().getParamNames(); default -> Collections.emptyList(); }; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/MimeType.java b/src/main/java/synfron/reshaper/burp/core/messages/MimeType.java index 81da7a3..75848e1 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/MimeType.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/MimeType.java @@ -61,17 +61,17 @@ public String getName() { return String.join(", ", names); } - public static MimeType get(String name) { - return switch (name.toLowerCase()) { - case "html" -> Html; - case "script" -> Script; - case "css" -> Css; - case "json" -> Json; - case "svg" -> Svg; - case "xml" -> OtherXml; - case "text" -> OtherText; - case "image", "jpeg", "png", "gif", "bmp" -> Image; - case "app" -> OtherBinary; + public static MimeType get(burp.api.montoya.http.MimeType mimeType) { + return switch (mimeType) { + case HTML -> Html; + case SCRIPT -> Script; + case CSS -> Css; + case JSON -> Json; + case IMAGE_SVG_XML -> Svg; + case XML -> OtherXml; + case PLAIN_TEXT, YAML, RTF -> OtherText; + case IMAGE_UNKNOWN, IMAGE_JPEG, IMAGE_PNG, IMAGE_GIF, IMAGE_BMP, IMAGE_TIFF -> Image; + case APPLICATION_FLASH, APPLICATION_UNKNOWN, LEGACY_SER_AMF, SOUND, VIDEO -> OtherBinary; default -> Unknown; }; } diff --git a/src/main/java/synfron/reshaper/burp/core/messages/WebSocketDataDirection.java b/src/main/java/synfron/reshaper/burp/core/messages/WebSocketDataDirection.java new file mode 100644 index 0000000..cf4023b --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/messages/WebSocketDataDirection.java @@ -0,0 +1,22 @@ +package synfron.reshaper.burp.core.messages; + +import burp.api.montoya.websocket.Direction; + +public enum WebSocketDataDirection { + Server, + Client; + + public static WebSocketDataDirection from(Direction direction) { + return switch (direction) { + case CLIENT_TO_SERVER -> Server; + case SERVER_TO_CLIENT -> Client; + }; + } + + public Direction toDirection() { + return switch (this) { + case Server -> Direction.CLIENT_TO_SERVER; + case Client -> Direction.SERVER_TO_CLIENT; + }; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/messages/WebSocketEventInfo.java b/src/main/java/synfron/reshaper/burp/core/messages/WebSocketEventInfo.java new file mode 100644 index 0000000..4197277 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/messages/WebSocketEventInfo.java @@ -0,0 +1,68 @@ +package synfron.reshaper.burp.core.messages; + +import burp.api.montoya.http.message.requests.HttpRequest; +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.BurpTool; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.vars.Variables; + +import java.util.function.BiConsumer; + +public class WebSocketEventInfo extends EventInfo { + @Getter + private final WebSocketMessageType messageType; + @Getter + private final Variables sessionVariables; + @Getter + private WebSocketDataDirection dataDirection; + @Getter + private final WebSocketDataDirection initialDataDirection; + @Getter + private BiConsumer messageSender; + @Getter + private T data; + + public WebSocketEventInfo(WebSocketMessageType messageType, Variables sessionVariables, WebSocketDataDirection dataDirection, BurpTool burpTool, BiConsumer messageSender, HttpRequest httpRequest, T data) { + super(burpTool, httpRequest); + this.messageType = messageType; + this.sessionVariables = sessionVariables; + this.initialDataDirection = dataDirection; + this.dataDirection = dataDirection; + this.httpProtocol = httpRequest.httpService().secure() ? "wss" : "ws"; + this.messageSender = messageSender; + this.data = data; + } + + public void setDataDirection(WebSocketDataDirection dataDirection) { + this.dataDirection = dataDirection; + changed = true; + } + + public void setText(String text) { + if (data instanceof String) { + this.data = (T) text; + } else { + this.data = (T)encoder.encode(text); + } + changed = true; + } + + public String getText() { + if (data instanceof String) { + return (String)data; + } else { + return encoder.decode((byte[])data); + } + } + + @Override + public boolean isSecure() { + return StringUtils.equalsIgnoreCase("wss", httpProtocol); + } + + @Override + public ProtocolType getProtocolType() { + return ProtocolType.WebSocket; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/messages/WebSocketMessageType.java b/src/main/java/synfron/reshaper/burp/core/messages/WebSocketMessageType.java new file mode 100644 index 0000000..3e93187 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/messages/WebSocketMessageType.java @@ -0,0 +1,6 @@ +package synfron.reshaper.burp.core.messages; + +public enum WebSocketMessageType { + Text, + Binary +} diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpBody.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpBody.java similarity index 92% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpBody.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpBody.java index 9a25fc5..d76375c 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpBody.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpBody.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; import synfron.reshaper.burp.core.messages.Encoder; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpCookies.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpCookies.java similarity index 98% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpCookies.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpCookies.java index 2bb8ad0..9441574 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpCookies.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpCookies.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpEntity.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpEntity.java similarity index 57% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpEntity.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpEntity.java index e34e4ff..5e3c237 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpEntity.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpEntity.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; public abstract class HttpEntity { public abstract boolean isChanged(); diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpHeaders.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpHeaders.java similarity index 98% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpHeaders.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpHeaders.java index 75f27c9..9f74cc6 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpHeaders.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpHeaders.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; import synfron.reshaper.burp.core.utils.*; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestHeaders.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestHeaders.java similarity index 75% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestHeaders.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestHeaders.java index 5de5ead..69c39fe 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestHeaders.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestHeaders.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; import java.util.List; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestMessage.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestMessage.java similarity index 58% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestMessage.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestMessage.java index ad30afe..0b58b17 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestMessage.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestMessage.java @@ -1,32 +1,37 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; -import burp.BurpExtender; -import burp.IRequestInfo; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.http.message.headers.HttpHeader; +import burp.api.montoya.http.message.requests.HttpRequest; import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.exceptions.WrappedException; import synfron.reshaper.burp.core.messages.ContentType; import synfron.reshaper.burp.core.messages.Encoder; -import synfron.reshaper.burp.core.utils.CollectionUtils; import synfron.reshaper.burp.core.utils.SetItemPlacement; +import synfron.reshaper.burp.core.utils.Url; -import java.net.MalformedURLException; -import java.net.URL; import java.util.Arrays; import java.util.stream.Collectors; import java.util.stream.Stream; public class HttpRequestMessage extends HttpEntity { + private HttpRequest httpRequest; private final byte[] request; private final Encoder encoder; - private IRequestInfo requestInfo; private boolean changed; private HttpRequestStatusLine statusLine; private HttpHeaders headers; private HttpBody body; + private boolean initialized; + + public HttpRequestMessage(HttpRequest httpRequest, Encoder encoder) { + this.httpRequest = httpRequest; + this.request = httpRequest != null ? httpRequest.asBytes().getBytes() : new byte[0]; + this.encoder = encoder; + } public HttpRequestMessage(byte[] request, Encoder encoder) { - this.request = request != null ? request : new byte[0]; + this.request = request; this.encoder = encoder; } @@ -38,23 +43,27 @@ public boolean isChanged() { (body != null && body.isChanged()); } - private IRequestInfo getRequestInfo() { - if (requestInfo == null) { - requestInfo = BurpExtender.getCallbacks().getHelpers().analyzeRequest(request); + private void initialize() { + if (!initialized) { + if (httpRequest == null) { + httpRequest = HttpRequest.httpRequest(ByteArray.byteArray(request)); + } if (!encoder.isUseDefault() && encoder.isAutoSet() && !getContentType().isTextBased()) { encoder.setEncoding("default", true); } + initialized = true; } - return requestInfo; } public ContentType getContentType() { - return ContentType.get(getRequestInfo().getContentType()); + initialize(); + return ContentType.get(httpRequest.contentType()); } public HttpRequestStatusLine getStatusLine() { if (statusLine == null) { - statusLine = new HttpRequestStatusLine(getRequestInfo().getHeaders().stream().findFirst().orElse("")); + initialize(); + statusLine = new HttpRequestStatusLine(httpRequest.headers().stream().map(HttpHeader::toString).findFirst().orElse("")); } return statusLine; } @@ -66,7 +75,7 @@ public void setStatusLine(String statusLine) { public HttpHeaders getHeaders() { if (headers == null) { - headers = new HttpRequestHeaders(getRequestInfo().getHeaders().stream().skip(1).collect(Collectors.toList())); + headers = new HttpRequestHeaders(httpRequest.headers().stream().map(HttpHeader::toString).skip(1).collect(Collectors.toList())); } return headers; } @@ -80,7 +89,7 @@ public void setHeaders(String headers) { public HttpBody getBody() { if (this.body == null) { - byte[] body = Arrays.copyOfRange(request, getRequestInfo().getBodyOffset(), request.length); + byte[] body = httpRequest.body().getBytes(); this.body = new HttpBody(body, encoder); } return this.body; @@ -92,15 +101,10 @@ public void setBody(String body) { } public void setUrl(String urlStr) { - try { - URL url = new URL(urlStr); - setUrl(url); - } catch (MalformedURLException e) { - throw new WrappedException(e); - } + setUrl(new Url(urlStr)); } - public void setUrl(URL url) { + public void setUrl(Url url) { getStatusLine().setUrl(url.getFile().startsWith("/") ? url.getFile() : "/" + url.getFile()); getHeaders().setHeader("Host", url.getAuthority(), SetItemPlacement.Only); } @@ -108,20 +112,21 @@ public void setUrl(URL url) { public byte[] getValue() { return !isChanged() ? getAdjustedRequest(request) : - BurpExtender.getCallbacks().getHelpers().buildHttpMessage( - Stream.concat(Stream.of(getStatusLine().getValue()), getHeaders().getValue().stream()).collect(Collectors.toList()), - getBody().getValue() - ); + asHttpRequest().asBytes().getBytes(); } - private byte[] getAdjustedRequest(byte[] request) { - IRequestInfo requestInfo = BurpExtender.getCallbacks().getHelpers().analyzeRequest(request); - return BurpExtender.getCallbacks().getHelpers().buildHttpMessage( - CollectionUtils.splitNewLines(requestInfo.getHeaders()), - Arrays.copyOfRange(request, requestInfo.getBodyOffset(), request.length) + public HttpRequest asHttpRequest() { + return HttpRequest.httpRequest( + null, + Stream.concat(Stream.of(getStatusLine().getValue()), getHeaders().getValue().stream()).collect(Collectors.toList()), + ByteArray.byteArray(getBody().getValue()) ); } + private byte[] getAdjustedRequest(byte[] request) { + return HttpRequest.httpRequest(ByteArray.byteArray(request)).asBytes().getBytes(); + } + public String getText() { return encoder.decode(getValue()); } diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestQueryParams.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestQueryParams.java similarity index 96% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestQueryParams.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestQueryParams.java index 9327a90..5b6318c 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestQueryParams.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestQueryParams.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; import lombok.Getter; import org.apache.http.NameValuePair; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestStatusLine.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestStatusLine.java similarity index 96% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestStatusLine.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestStatusLine.java index 10bd13e..951022b 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestStatusLine.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestStatusLine.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.utils.CollectionUtils; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestUri.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestUri.java similarity index 96% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestUri.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestUri.java index 3a92242..d552d16 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpRequestUri.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpRequestUri.java @@ -1,9 +1,8 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; import lombok.Getter; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.NameValuePair; import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URLEncodedUtils; import synfron.reshaper.burp.core.exceptions.WrappedException; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpResponseHeaders.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpResponseHeaders.java similarity index 76% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpResponseHeaders.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpResponseHeaders.java index 6808587..63d11bb 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpResponseHeaders.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpResponseHeaders.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; import java.util.List; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpResponseMessage.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpResponseMessage.java similarity index 55% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpResponseMessage.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpResponseMessage.java index a80ad01..0ff5be4 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpResponseMessage.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpResponseMessage.java @@ -1,12 +1,11 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; -import burp.BurpExtender; -import burp.IResponseInfo; -import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.messages.ContentType; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.http.message.headers.HttpHeader; +import burp.api.montoya.http.message.responses.HttpResponse; +import org.apache.commons.lang3.ObjectUtils; import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.messages.MimeType; -import synfron.reshaper.burp.core.utils.CollectionUtils; import java.util.Arrays; import java.util.stream.Collectors; @@ -16,16 +15,23 @@ public class HttpResponseMessage extends HttpEntity { + private HttpResponse httpResponse; private final byte[] response; private final Encoder encoder; - private IResponseInfo responseInfo; private boolean changed; private HttpResponseStatusLine statusLine; private HttpHeaders headers; private HttpBody body; + private boolean initialized; + + public HttpResponseMessage(HttpResponse httpResponse, Encoder encoder) { + this.httpResponse = httpResponse; + this.response = httpResponse != null ? httpResponse.asBytes().getBytes() : new byte[0]; + this.encoder = encoder; + } public HttpResponseMessage(byte[] response, Encoder encoder) { - this.response = response != null ? response : new byte[0]; + this.response = response; this.encoder = encoder; } @@ -37,28 +43,27 @@ public boolean isChanged() { (body != null && body.isChanged()); } - private IResponseInfo getResponseInfo() { - if (responseInfo == null) { - responseInfo = BurpExtender.getCallbacks().getHelpers().analyzeResponse(response); + private void initialize() { + if (!initialized) { + if (httpResponse == null) { + httpResponse = HttpResponse.httpResponse(ByteArray.byteArray(response)); + } if (!encoder.isUseDefault() && encoder.isAutoSet() && !getMimeType().isTextBased()) { encoder.setEncoding("default", true); } + initialized = true; } - return responseInfo; } public MimeType getMimeType() { - IResponseInfo responseInfo = getResponseInfo(); - String statedMimeType = responseInfo.getStatedMimeType(); - return MimeType.get(statedMimeType.equalsIgnoreCase("svg") ? - statedMimeType : - StringUtils.defaultIfEmpty(responseInfo.getInferredMimeType(), statedMimeType) - ); + initialize(); + return MimeType.get(ObjectUtils.defaultIfNull(httpResponse.statedMimeType(), httpResponse.inferredMimeType())); } public HttpResponseStatusLine getStatusLine() { if (statusLine == null) { - statusLine = new HttpResponseStatusLine(getResponseInfo().getHeaders().stream().findFirst().orElse("")); + initialize(); + statusLine = new HttpResponseStatusLine(httpResponse.headers().stream().map(HttpHeader::toString).findFirst().orElse("")); } return statusLine; } @@ -70,7 +75,8 @@ public void setStatusLine(String statusLine) { public HttpHeaders getHeaders() { if (headers == null) { - headers = new HttpResponseHeaders(getResponseInfo().getHeaders().stream().skip(1).collect(toList())); + initialize(); + headers = new HttpResponseHeaders(httpResponse.headers().stream().skip(1).map(HttpHeader::toString).collect(toList())); } return headers; } @@ -84,7 +90,8 @@ public void setHeaders(String headers) { public HttpBody getBody() { if (this.body == null) { - byte[] body = Arrays.copyOfRange(response, getResponseInfo().getBodyOffset(), response.length); + initialize(); + byte[] body = httpResponse.body().getBytes(); this.body = new HttpBody(body, encoder); } return this.body; @@ -98,20 +105,20 @@ public void setBody(String body) { public byte[] getValue() { return !isChanged() ? getAdjustedResponse(response) : - BurpExtender.getCallbacks().getHelpers().buildHttpMessage( - Stream.concat(Stream.of(getStatusLine().getValue()), getHeaders().getValue().stream()).collect(Collectors.toList()), - getBody().getValue() - ); + asHttpResponse().asBytes().getBytes(); } - private byte[] getAdjustedResponse(byte[] response) { - IResponseInfo responseInfo = BurpExtender.getCallbacks().getHelpers().analyzeResponse(response); - return BurpExtender.getCallbacks().getHelpers().buildHttpMessage( - CollectionUtils.splitNewLines(responseInfo.getHeaders()), - Arrays.copyOfRange(response, responseInfo.getBodyOffset(), response.length) + public HttpResponse asHttpResponse() { + return HttpResponse.httpResponse( + Stream.concat(Stream.of(getStatusLine().getValue()), getHeaders().getValue().stream()).collect(Collectors.toList()), + ByteArray.byteArray(getBody().getValue()) ); } + private byte[] getAdjustedResponse(byte[] response) { + return HttpResponse.httpResponse(ByteArray.byteArray(response)).asBytes().getBytes(); + } + public String getText() { return encoder.decode(getValue()); } diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpResponseStatusLine.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpResponseStatusLine.java similarity index 96% rename from src/main/java/synfron/reshaper/burp/core/messages/entities/HttpResponseStatusLine.java rename to src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpResponseStatusLine.java index e6ff7a1..53b1e36 100644 --- a/src/main/java/synfron/reshaper/burp/core/messages/entities/HttpResponseStatusLine.java +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/http/HttpResponseStatusLine.java @@ -1,4 +1,4 @@ -package synfron.reshaper.burp.core.messages.entities; +package synfron.reshaper.burp.core.messages.entities.http; import lombok.Getter; import org.apache.commons.lang3.StringUtils; diff --git a/src/main/java/synfron/reshaper/burp/core/messages/entities/websocket/WebSocketMessage.java b/src/main/java/synfron/reshaper/burp/core/messages/entities/websocket/WebSocketMessage.java new file mode 100644 index 0000000..f2217ea --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/messages/entities/websocket/WebSocketMessage.java @@ -0,0 +1,4 @@ +package synfron.reshaper.burp.core.messages.entities.websocket; + +public class WebSocketMessage { +} diff --git a/src/main/java/synfron/reshaper/burp/core/rules/IHttpRuleOperation.java b/src/main/java/synfron/reshaper/burp/core/rules/IHttpRuleOperation.java new file mode 100644 index 0000000..1ce3361 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/rules/IHttpRuleOperation.java @@ -0,0 +1,4 @@ +package synfron.reshaper.burp.core.rules; + +public interface IHttpRuleOperation { +} diff --git a/src/main/java/synfron/reshaper/burp/core/rules/IRuleOperation.java b/src/main/java/synfron/reshaper/burp/core/rules/IRuleOperation.java index 3f6cb9e..0177675 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/IRuleOperation.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/IRuleOperation.java @@ -1,9 +1,23 @@ package synfron.reshaper.burp.core.rules; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.WebSocketEventInfo; +import synfron.reshaper.burp.core.vars.GlobalVariables; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.Variables; + import java.io.Serializable; public interface IRuleOperation> extends Serializable { RuleOperationType getType(); - T copy(); + IRuleOperation copy(); + default Variables getVariables(VariableSource variableSource, EventInfo eventInfo) { + return switch (variableSource) { + case Event -> eventInfo.getVariables(); + case Global -> GlobalVariables.get(); + case Session -> eventInfo instanceof WebSocketEventInfo ? ((WebSocketEventInfo)eventInfo).getSessionVariables() : null; + default -> null; + }; + } } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/IWebSocketRuleOperation.java b/src/main/java/synfron/reshaper/burp/core/rules/IWebSocketRuleOperation.java new file mode 100644 index 0000000..1181a53 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/rules/IWebSocketRuleOperation.java @@ -0,0 +1,4 @@ +package synfron.reshaper.burp.core.rules; + +public interface IWebSocketRuleOperation { +} diff --git a/src/main/java/synfron/reshaper/burp/core/rules/Rule.java b/src/main/java/synfron/reshaper/burp/core/rules/Rule.java index 9f37943..0eb32f2 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/Rule.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/Rule.java @@ -7,13 +7,9 @@ import synfron.reshaper.burp.core.events.PropertyChangedEvent; import synfron.reshaper.burp.core.rules.thens.Then; import synfron.reshaper.burp.core.rules.whens.When; -import synfron.reshaper.burp.core.utils.ObjectUtils; import synfron.reshaper.burp.core.utils.Serializer; import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; public class Rule implements Serializable { @Getter @@ -28,6 +24,8 @@ public class Rule implements Serializable { private boolean autoRun = true; @Getter private String name; + @Getter + private transient boolean diagnosticsEnabled; public void setName(String name) { this.name = name; @@ -44,6 +42,11 @@ public void setAutoRun(boolean autoRun) { propertyChangedEvent.invoke(new PropertyChangedArgs(this, "autoRun", autoRun)); } + public void setDiagnosticsEnabled(boolean diagnosticsEnabled) { + this.diagnosticsEnabled = diagnosticsEnabled; + propertyChangedEvent.invoke(new PropertyChangedArgs(this, "diagnosticsEnabled", diagnosticsEnabled)); + } + @Override public String toString() { return name; diff --git a/src/main/java/synfron/reshaper/burp/core/rules/RulesEngine.java b/src/main/java/synfron/reshaper/burp/core/rules/RulesEngine.java index 5ba3359..46bd258 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/RulesEngine.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/RulesEngine.java @@ -2,7 +2,7 @@ import lombok.Getter; import org.mozilla.javascript.RhinoException; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; import synfron.reshaper.burp.core.rules.thens.Then; import synfron.reshaper.burp.core.rules.whens.When; import synfron.reshaper.burp.core.utils.Log; @@ -12,7 +12,7 @@ public class RulesEngine { @Getter private final RulesRegistry rulesRegistry = new RulesRegistry(); - private boolean match(When[] whens, IEventInfo eventInfo) + private boolean match(When[] whens, EventInfo eventInfo) { boolean isMatch = true; boolean first = true; @@ -35,7 +35,7 @@ private boolean match(When[] whens, IEventInfo eventInfo) return isMatch; } - private RuleResponse perform(Then[] thens, IEventInfo eventInfo) + private RuleResponse perform(Then[] thens, EventInfo eventInfo) { RuleResponse thenResult = RuleResponse.Continue; for (Then then : thens) @@ -50,11 +50,10 @@ private RuleResponse perform(Then[] thens, IEventInfo eventInfo) return thenResult; } - public RuleResponse run(IEventInfo eventInfo) + public RuleResponse run(EventInfo eventInfo) { Rule[] rules = rulesRegistry.getRules(); try { - if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logStart(eventInfo); for (Rule rule : rules) { if (rule.isAutoRun()) { RuleResponse thenResult = run(eventInfo, rule); @@ -64,14 +63,20 @@ public RuleResponse run(IEventInfo eventInfo) } } } finally { - if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logEnd(eventInfo); + if (eventInfo.getDiagnostics().hasLogs()) eventInfo.getDiagnostics().logStart(eventInfo); + if (eventInfo.getDiagnostics().hasLogs()) eventInfo.getDiagnostics().logEnd(eventInfo); } return RuleResponse.Continue; } - public RuleResponse run(IEventInfo eventInfo, Rule rule) + public RuleResponse run(EventInfo eventInfo, Rule rule) { RuleResponse thenResult = RuleResponse.Continue; + boolean ruleDiagnosticsEnabled = eventInfo.getDiagnostics().isRuleEnabled(); + boolean currentRuleDiagnosticsEnabled = rule.isDiagnosticsEnabled(); + if (!ruleDiagnosticsEnabled && currentRuleDiagnosticsEnabled) { + eventInfo.getDiagnostics().setRuleEnabled(true); + } if (rule.isEnabled() && eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logStart(rule); try { @@ -86,6 +91,9 @@ public RuleResponse run(IEventInfo eventInfo, Rule rule) } finally { if (rule.isEnabled() && eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logEnd(rule); } + if (!ruleDiagnosticsEnabled && currentRuleDiagnosticsEnabled) { + eventInfo.getDiagnostics().setRuleEnabled(false); + } return thenResult; } } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/Diagnostics.java b/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/Diagnostics.java index ea47a02..1b65c68 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/Diagnostics.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/Diagnostics.java @@ -5,7 +5,9 @@ import lombok.Setter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpEventInfo; +import synfron.reshaper.burp.core.messages.WebSocketEventInfo; import synfron.reshaper.burp.core.rules.MatchType; import synfron.reshaper.burp.core.rules.Rule; import synfron.reshaper.burp.core.rules.thens.Then; @@ -23,7 +25,11 @@ public class Diagnostics implements IDiagnostics { private List records; @Getter @Setter - private boolean enabled; + private boolean ruleEnabled; + @Getter @Setter + private boolean eventEnabled; + private DiagnosticRecord startRecord; + private DiagnosticRecord endRecord; @Override public void logCompare(When when, List> properties, MatchType matchType, Object matcher, Object value, boolean result) { @@ -107,20 +113,49 @@ public void logEnd(Rule rule) { } @Override - public void logStart(IEventInfo eventInfo) { - getRecords().add(new DiagnosticRecord(DiagnosticEntityType.StartEvent, String.format("%s: %s\n", eventInfo.getDataDirection(), eventInfo.getUrl()))); + public void logStart(EventInfo eventInfo) { + if (eventInfo instanceof HttpEventInfo) { + HttpEventInfo httpEventInfo = (HttpEventInfo)eventInfo; + logStart(httpEventInfo); + } else if (eventInfo instanceof WebSocketEventInfo) { + WebSocketEventInfo webSocketEventInfo = (WebSocketEventInfo)eventInfo; + logStart(webSocketEventInfo); + } } @Override - public void logEnd(IEventInfo eventInfo) { - getRecords().add(new DiagnosticRecord(DiagnosticEntityType.EndEvent, String.format("End %s\n", eventInfo.getDataDirection().toString()))); + public void logEnd(EventInfo eventInfo) { + if (eventInfo instanceof HttpEventInfo) { + HttpEventInfo httpEventInfo = (HttpEventInfo)eventInfo; + logEnd(httpEventInfo); + } else if (eventInfo instanceof WebSocketEventInfo) { + WebSocketEventInfo webSocketEventInfo = (WebSocketEventInfo)eventInfo; + logEnd(webSocketEventInfo); + } + } + + private void logStart(HttpEventInfo eventInfo) { + startRecord = new DiagnosticRecord(DiagnosticEntityType.StartEvent, String.format("%s: %s\n", eventInfo.getInitialDataDirection(), eventInfo.getInitialHttpRequest().url())); + } + + private void logStart(WebSocketEventInfo eventInfo) { + startRecord = new DiagnosticRecord(DiagnosticEntityType.StartEvent, String.format("%s: %s\n", eventInfo.getInitialDataDirection(), eventInfo.getInitialHttpRequest().url())); + } + + private void logEnd(HttpEventInfo eventInfo) { + endRecord = new DiagnosticRecord(DiagnosticEntityType.EndEvent, String.format("End %s\n", eventInfo.getDataDirection().toString())); + } + + private void logEnd(WebSocketEventInfo eventInfo) { + endRecord = new DiagnosticRecord(DiagnosticEntityType.EndEvent, String.format("End %s\n", eventInfo.getDataDirection().toString())); } @Override public String getLogs() { StringBuilder buffer = new StringBuilder(); if (records != null) { - int indent = 0; + int indent = 1; + buffer.append(startRecord.getLog()); DiagnosticEntityType lastEntity = null; for (DiagnosticRecord record : records) { if (record.getEntityType() != null) { @@ -135,10 +170,21 @@ public String getLogs() { } buffer.append("\t".repeat(indent)).append(record.getLog()); } + buffer.append(endRecord.getLog()); } return buffer.toString(); } + @Override + public boolean isEnabled() { + return ruleEnabled || eventEnabled; + } + + @Override + public boolean hasLogs() { + return records != null; + } + private List getRecords() { return records != null ? records : (records = new ArrayList<>()); } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/IDiagnostics.java b/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/IDiagnostics.java index ae65e37..c8b4c86 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/IDiagnostics.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/diagnostics/IDiagnostics.java @@ -1,7 +1,7 @@ package synfron.reshaper.burp.core.rules.diagnostics; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; import synfron.reshaper.burp.core.rules.MatchType; import synfron.reshaper.burp.core.rules.Rule; import synfron.reshaper.burp.core.rules.thens.Then; @@ -25,13 +25,21 @@ public interface IDiagnostics { void logEnd(Rule rule); - void logStart(IEventInfo eventInfo); + void logStart(EventInfo eventInfo); - void logEnd(IEventInfo eventInfo); + void logEnd(EventInfo eventInfo); String getLogs(); boolean isEnabled(); - void setEnabled(boolean enabled); + boolean isEventEnabled(); + + boolean isRuleEnabled(); + + boolean hasLogs(); + + void setRuleEnabled(boolean enabled); + + void setEventEnabled(boolean enabled); } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java index 590401d..4a1345b 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/Then.java @@ -2,10 +2,13 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; import synfron.reshaper.burp.core.rules.IRuleOperation; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.utils.Serializer; +import synfron.reshaper.burp.core.vars.Variable; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.Variables; @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, property = "@class") @JsonSubTypes({ @@ -14,6 +17,7 @@ @JsonSubTypes.Type(value = ThenDeleteValue.class), @JsonSubTypes.Type(value = ThenDeleteVariable.class), @JsonSubTypes.Type(value = ThenDrop.class), + @JsonSubTypes.Type(value = ThenIntercept.class), @JsonSubTypes.Type(value = ThenHighlight.class), @JsonSubTypes.Type(value = ThenComment.class), @JsonSubTypes.Type(value = ThenLog.class), @@ -27,13 +31,23 @@ @JsonSubTypes.Type(value = ThenRunProcess.class), @JsonSubTypes.Type(value = ThenBuildHttpMessage.class), @JsonSubTypes.Type(value = ThenParseHttpMessage.class), - @JsonSubTypes.Type(value = ThenSendRequest.class) + @JsonSubTypes.Type(value = ThenSendRequest.class), + @JsonSubTypes.Type(value = ThenSendMessage.class) }) public abstract class Then> implements IRuleOperation { - public abstract RuleResponse perform(IEventInfo eventInfo); + + public abstract RuleResponse perform(EventInfo eventInfo); @SuppressWarnings("unchecked") - public T copy() { - return (T)Serializer.copy(this); + public IRuleOperation copy() { + return Serializer.copy(this); + } + + protected void setVariable(VariableSource variableSource, EventInfo eventInfo, String variableName, String value) { + Variables variables = getVariables(variableSource, eventInfo); + if (variables != null) { + Variable variable = variables.add(variableName); + variable.setValue(value); + } } } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBreak.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBreak.java index 83bf845..036ebb0 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBreak.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBreak.java @@ -2,17 +2,19 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; -public class ThenBreak extends Then { +public class ThenBreak extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private RuleResponse breakType = RuleResponse.BreakThens; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue(this, false, breakType); return breakType; } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java index a0edc72..a8d89fc 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenBuildHttpMessage.java @@ -3,11 +3,13 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.DataDirection; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.messages.MessageValueHandler; -import synfron.reshaper.burp.core.messages.entities.HttpRequestMessage; -import synfron.reshaper.burp.core.messages.entities.HttpResponseMessage; +import synfron.reshaper.burp.core.messages.entities.http.HttpRequestMessage; +import synfron.reshaper.burp.core.messages.entities.http.HttpResponseMessage; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.thens.entities.buildhttpmessage.MessageValueSetter; @@ -19,9 +21,9 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public class ThenBuildHttpMessage extends Then { +public class ThenBuildHttpMessage extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter - private DataDirection dataDirection = DataDirection.Request; + private HttpDataDirection dataDirection = HttpDataDirection.Request; @Getter @Setter private VariableString starterHttpMessage; @Getter @Setter @@ -31,16 +33,13 @@ public class ThenBuildHttpMessage extends Then { @Getter @Setter private VariableString destinationVariableName; - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { try { - Variables variables = switch (destinationVariableSource) { - case Event -> eventInfo.getVariables(); - case Global -> GlobalVariables.get(); - default -> null; - }; + String value = dataDirection == HttpDataDirection.Request ? buildRequestMessage(eventInfo) : buildResponseMessage(eventInfo); + Variables variables = getVariables(destinationVariableSource, eventInfo); if (variables != null) { Variable variable = variables.add(destinationVariableName.getText(eventInfo)); - variable.setValue(dataDirection == DataDirection.Request ? buildRequestMessage(eventInfo) : buildResponseMessage(eventInfo)); + variable.setValue(value); } if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logProperties(this, false, Stream.concat( Stream.of( @@ -66,7 +65,7 @@ public RuleResponse perform(IEventInfo eventInfo) { return RuleResponse.Continue; } - private String buildRequestMessage(IEventInfo eventInfo) { + private String buildRequestMessage(EventInfo eventInfo) { HttpRequestMessage httpRequestMessage = new HttpRequestMessage(eventInfo.getEncoder().encode( VariableString.getTextOrDefault(eventInfo, starterHttpMessage, "") ), eventInfo.getEncoder()); @@ -83,7 +82,7 @@ private String buildRequestMessage(IEventInfo eventInfo) { return httpRequestMessage.getText(); } - private String buildResponseMessage(IEventInfo eventInfo) { + private String buildResponseMessage(EventInfo eventInfo) { HttpResponseMessage httpResponseMessage = new HttpResponseMessage(eventInfo.getEncoder().encode( VariableString.getTextOrDefault(eventInfo, starterHttpMessage, "") ), eventInfo.getEncoder()); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenComment.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenComment.java index 9e6d023..a4d1634 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenComment.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenComment.java @@ -2,21 +2,24 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpEventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.vars.VariableString; -public class ThenComment extends Then { +public class ThenComment extends Then implements IHttpRuleOperation { @Getter @Setter private VariableString text; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = true; try { - eventInfo.getRequestResponse().setComment(text.getText(eventInfo)); + HttpEventInfo httpEventInfo = (HttpEventInfo)eventInfo; + httpEventInfo.setAnnotations(httpEventInfo.getAnnotations().withComment(text.getText(eventInfo))); hasError = false; } finally { if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue(this, hasError, VariableString.getTextOrDefault(eventInfo, text, null)); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDelay.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDelay.java index ff83f75..4ef835b 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDelay.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDelay.java @@ -4,7 +4,9 @@ import lombok.Setter; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.utils.Log; @@ -12,13 +14,13 @@ import java.util.Arrays; -public class ThenDelay extends Then { +public class ThenDelay extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableString delay; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = false; try { Thread.sleep(ObjectUtils.defaultIfNull(delay.getInt(eventInfo), 0)); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteValue.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteValue.java index e8509a0..9504043 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteValue.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteValue.java @@ -2,19 +2,20 @@ import lombok.Getter; import lombok.Setter; +import synfron.reshaper.burp.core.messages.EventInfo; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.messages.MessageValueHandler; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.utils.DeleteItemPlacement; import synfron.reshaper.burp.core.utils.IItemPlacement; import synfron.reshaper.burp.core.vars.VariableString; -public class ThenDeleteValue extends Then { +public class ThenDeleteValue extends Then implements IHttpRuleOperation { @Getter @Setter - private MessageValue messageValue = MessageValue.HttpRequestBody; + private MessageValue messageValue; @Getter @Setter private VariableString identifier; @@ -23,7 +24,7 @@ public class ThenDeleteValue extends Then { private DeleteItemPlacement identifierPlacement = DeleteItemPlacement.Last; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = false; try { MessageValueHandler.setValue(eventInfo, messageValue, identifier, IItemPlacement.toSet(identifierPlacement), null); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteVariable.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteVariable.java index ae09509..8aab557 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteVariable.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDeleteVariable.java @@ -2,15 +2,16 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; -import synfron.reshaper.burp.core.vars.GlobalVariables; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.core.vars.Variables; -public class ThenDeleteVariable extends Then { +public class ThenDeleteVariable extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableSource targetSource = VariableSource.Global; @@ -18,14 +19,10 @@ public class ThenDeleteVariable extends Then { private VariableString variableName; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = false; try { - Variables variables = switch (targetSource) { - case Event -> eventInfo.getVariables(); - case Global -> GlobalVariables.get(); - default -> null; - }; + Variables variables = getVariables(targetSource, eventInfo); variables.remove(variableName.getText(eventInfo)); } catch (Exception e) { hasError = true; diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDrop.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDrop.java index 7e0ca4b..d72a56b 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDrop.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenDrop.java @@ -2,15 +2,17 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; -public class ThenDrop extends Then { +public class ThenDrop extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private boolean dropMessage = true; - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { eventInfo.setShouldDrop(dropMessage); if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue(this, false, dropMessage); return RuleResponse.Continue; diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenEvaluate.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenEvaluate.java index a29af1d..b25775e 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenEvaluate.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenEvaluate.java @@ -4,15 +4,20 @@ import lombok.Setter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.thens.entities.evaluate.Operation; -import synfron.reshaper.burp.core.vars.*; +import synfron.reshaper.burp.core.vars.Variable; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.core.vars.Variables; import java.util.Arrays; -public class ThenEvaluate extends Then { +public class ThenEvaluate extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableString x; @@ -28,18 +33,18 @@ public class ThenEvaluate extends Then { private VariableString destinationVariableName; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = true; String result = null; + Double value1 = null; + Double value2 = null; try { - Variables variables = switch (destinationVariableSource) { - case Event -> eventInfo.getVariables(); - case Global -> GlobalVariables.get(); - default -> null; - }; + Variables variables = getVariables(destinationVariableSource, eventInfo); if (variables != null) { Variable variable = variables.add(destinationVariableName.getText(eventInfo)); - result = evaluate(eventInfo); + value1 = operation.getInputs() > 0 ? VariableString.getDoubleOrDefault(eventInfo, x, null) : null; + value2 = operation.getInputs() > 1 ? VariableString.getDoubleOrDefault(eventInfo, y, null) : null; + result = evaluate(value1, value2); if (result != null) { variable.setValue(result); } @@ -47,8 +52,8 @@ public RuleResponse perform(IEventInfo eventInfo) { hasError = result == null; } finally { if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logProperties(this, hasError, Arrays.asList( - Pair.of("X", VariableString.getTextOrDefault(eventInfo, x, null)), - Pair.of("Y", VariableString.getTextOrDefault(eventInfo, y, null)), + Pair.of("X", value1), + Pair.of("Y", value2), Pair.of("destinationVariableSource", destinationVariableSource), Pair.of("destinationVariableName", VariableString.getTextOrDefault(eventInfo, destinationVariableName, null)), Pair.of("result", result) @@ -57,9 +62,7 @@ public RuleResponse perform(IEventInfo eventInfo) { return RuleResponse.Continue; } - private String evaluate(IEventInfo eventInfo) { - Double value1 = operation.getInputs() > 0 ? VariableString.getDoubleOrDefault(eventInfo, x, null) : null; - Double value2 = operation.getInputs() > 1 ? VariableString.getDoubleOrDefault(eventInfo, y, null) : null; + private String evaluate(Double value1, Double value2) { String result = null; if ((operation.getInputs() == 1 && value1 != null) || (operation.getInputs() == 2 && value1 != null && value2 != null)) { diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenHighlight.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenHighlight.java index 81d4108..69d9d2f 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenHighlight.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenHighlight.java @@ -2,19 +2,27 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpEventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; -public class ThenHighlight extends Then { +public class ThenHighlight extends Then implements IHttpRuleOperation { @Getter @Setter private HighlightColor color = HighlightColor.None; @Override - public RuleResponse perform(IEventInfo eventInfo) { - eventInfo.getRequestResponse().setHighlight(color.getValue()); - if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue(this, false, color.getValue()); + public RuleResponse perform(EventInfo eventInfo) { + boolean hasError = true; + try { + HttpEventInfo httpEventInfo = (HttpEventInfo)eventInfo; + httpEventInfo.setAnnotations(httpEventInfo.getAnnotations().withHighlightColor(color.highlightColor)); + hasError = false; + } finally { + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue(this, hasError, color.getValue()); + } return RuleResponse.Continue; } @@ -24,21 +32,23 @@ public RuleOperationType getType() { } public enum HighlightColor { - None(null), - Red("red"), - Orange("orange"), - Yellow("yellow"), - Green("green"), - Cyan("cyan"), - Blue("blue"), - Pink("pink"), - Magenta("magenta"), - Gray("gray"); + None(null, burp.api.montoya.core.HighlightColor.NONE), + Red("red", burp.api.montoya.core.HighlightColor.RED), + Orange("orange", burp.api.montoya.core.HighlightColor.ORANGE), + Yellow("yellow", burp.api.montoya.core.HighlightColor.YELLOW), + Green("green", burp.api.montoya.core.HighlightColor.GREEN), + Cyan("cyan", burp.api.montoya.core.HighlightColor.CYAN), + Blue("blue", burp.api.montoya.core.HighlightColor.BLUE), + Pink("pink", burp.api.montoya.core.HighlightColor.PINK), + Magenta("magenta", burp.api.montoya.core.HighlightColor.MAGENTA), + Gray("gray", burp.api.montoya.core.HighlightColor.GRAY); private final String value; + private final burp.api.montoya.core.HighlightColor highlightColor; - HighlightColor(String value) { + HighlightColor(String value, burp.api.montoya.core.HighlightColor highlightColor) { this.value = value; + this.highlightColor = highlightColor; } public String getValue() { diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenIntercept.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenIntercept.java new file mode 100644 index 0000000..f0e20be --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenIntercept.java @@ -0,0 +1,30 @@ +package synfron.reshaper.burp.core.rules.thens; + +import lombok.Getter; +import lombok.Setter; +import synfron.reshaper.burp.core.InterceptResponse; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; +import synfron.reshaper.burp.core.rules.RuleOperationType; +import synfron.reshaper.burp.core.rules.RuleResponse; + +public class ThenIntercept extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { + @Getter @Setter + private InterceptResponse interceptResponse = InterceptResponse.UserDefined; + + public RuleResponse perform(EventInfo eventInfo) { + eventInfo.setDefaultInterceptResponse(interceptResponse); + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue(this, false, interceptResponse); + return RuleResponse.Continue; + } + + @Override + public RuleOperationType getType() { + return ThenType.Intercept; + } + + public static InterceptResponse[] getSupportedResponses() { + return new InterceptResponse[] { InterceptResponse.UserDefined, InterceptResponse.Disable, InterceptResponse.Intercept }; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenLog.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenLog.java index 2b0021a..63ce1ac 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenLog.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenLog.java @@ -2,19 +2,21 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.utils.Log; import synfron.reshaper.burp.core.vars.VariableString; -public class ThenLog extends Then { +public class ThenLog extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableString text; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = true; try { Log.get().withMessage(text.getText(eventInfo)).log(); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenParseHttpMessage.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenParseHttpMessage.java index 255b05d..fdfdf02 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenParseHttpMessage.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenParseHttpMessage.java @@ -1,35 +1,38 @@ package synfron.reshaper.burp.core.rules.thens; -import burp.BurpExtender; import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.DataDirection; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.messages.MessageValueHandler; -import synfron.reshaper.burp.core.messages.entities.HttpRequestMessage; -import synfron.reshaper.burp.core.messages.entities.HttpResponseMessage; +import synfron.reshaper.burp.core.messages.entities.http.HttpRequestMessage; +import synfron.reshaper.burp.core.messages.entities.http.HttpResponseMessage; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.thens.entities.parsehttpmessage.MessageValueGetter; import synfron.reshaper.burp.core.vars.*; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -public class ThenParseHttpMessage extends Then { +public class ThenParseHttpMessage extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter - private DataDirection dataDirection = DataDirection.Request; + private HttpDataDirection dataDirection = HttpDataDirection.Request; @Getter @Setter private VariableString httpMessage; @Getter @Setter private List messageValueGetters = new ArrayList<>(); - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { try { List> variables; - if (dataDirection == DataDirection.Request) { + if (dataDirection == HttpDataDirection.Request) { variables = parseRequestMessage(eventInfo); } else { variables = parseResponseMessage(eventInfo); @@ -48,7 +51,7 @@ public RuleResponse perform(IEventInfo eventInfo) { return RuleResponse.Continue; } - private List> parseRequestMessage(IEventInfo eventInfo) { + private List> parseRequestMessage(EventInfo eventInfo) { HttpRequestMessage httpRequestMessage = new HttpRequestMessage(eventInfo.getEncoder().encode( VariableString.getTextOrDefault(eventInfo, httpMessage, "") ), eventInfo.getEncoder()); @@ -67,7 +70,7 @@ private List> parseRequestMessage(IEventInfo eventInfo) { return variables; } - private List> parseResponseMessage(IEventInfo eventInfo) { + private List> parseResponseMessage(EventInfo eventInfo) { HttpResponseMessage httpResponseMessage = new HttpResponseMessage(eventInfo.getEncoder().encode( VariableString.getTextOrDefault(eventInfo, httpMessage, "") ), eventInfo.getEncoder()); @@ -86,12 +89,8 @@ private List> parseResponseMessage(IEventInfo eventInfo) { return variables; } - private Pair setVariable(IEventInfo eventInfo, VariableSource variableSource, String variableName, String value) { - Variables variables = switch (variableSource) { - case Event -> eventInfo.getVariables(); - case Global -> GlobalVariables.get(); - default -> null; - }; + private Pair setVariable(EventInfo eventInfo, VariableSource variableSource, String variableName, String value) { + Variables variables = getVariables(variableSource, eventInfo); Variable variable; if (variables != null) { variable = variables.add(variableName); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenPrompt.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenPrompt.java index 49c2fc0..9888993 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenPrompt.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenPrompt.java @@ -7,16 +7,19 @@ import synfron.reshaper.burp.core.events.MessageArgs; import synfron.reshaper.burp.core.events.message.*; import synfron.reshaper.burp.core.exceptions.WrappedException; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; -import synfron.reshaper.burp.core.vars.*; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableString; import java.util.Arrays; import java.util.UUID; import java.util.concurrent.TimeUnit; -public class ThenPrompt extends Then { +public class ThenPrompt extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableString description; @Getter @Setter @@ -31,7 +34,7 @@ public class ThenPrompt extends Then { private VariableString captureVariableName; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = false; boolean failed = false; boolean complete = false; @@ -54,7 +57,7 @@ public RuleResponse perform(IEventInfo eventInfo) { if (messageWaiter.waitForMessage(failAfterInMilliseconds, TimeUnit.MILLISECONDS)) { output = messageWaiter.getMessage().getResponse(); if (output != null) { - setVariable(eventInfo, captureVariableName, output); + setVariable(captureVariableSource, eventInfo, captureVariableName, output); } else { failed = true; } @@ -86,18 +89,6 @@ public RuleResponse perform(IEventInfo eventInfo) { return failed && breakAfterFailure ? RuleResponse.BreakRules : RuleResponse.Continue; } - private void setVariable(IEventInfo eventInfo, String variableName, String value) { - Variables variables = switch (captureVariableSource) { - case Event -> eventInfo.getVariables(); - case Global -> GlobalVariables.get(); - default -> null; - }; - if (variables != null) { - Variable variable = variables.add(variableName); - variable.setValue(value); - } - } - @Override public RuleOperationType getType() { return ThenType.Prompt; diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunProcess.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunProcess.java index d11bd31..06c08e2 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunProcess.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunProcess.java @@ -7,7 +7,9 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import synfron.reshaper.burp.core.exceptions.WrappedException; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.utils.Log; @@ -21,7 +23,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; -public class ThenRunProcess extends Then { +public class ThenRunProcess extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableString command; @Getter @Setter @@ -46,7 +48,7 @@ public class ThenRunProcess extends Then { private VariableString captureVariableName; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = false; boolean failed = false; boolean complete = false; @@ -95,7 +97,7 @@ public RuleResponse perform(IEventInfo eventInfo) { bufferedWriter.flush(); bufferedWriter.close(); output = stringWriter.toString(); - setVariable(eventInfo, captureVariableName, output); + setVariable(captureVariableSource, eventInfo, captureVariableName, output); } } @@ -122,19 +124,7 @@ public RuleResponse perform(IEventInfo eventInfo) { return failed && breakAfterFailure ? RuleResponse.BreakRules : RuleResponse.Continue; } - private void setVariable(IEventInfo eventInfo, String variableName, String value) { - Variables variables = switch (captureVariableSource) { - case Event -> eventInfo.getVariables(); - case Global -> GlobalVariables.get(); - default -> null; - }; - if (variables != null) { - Variable variable = variables.add(variableName); - variable.setValue(value); - } - } - - private String getVariableName(IEventInfo eventInfo) { + private String getVariableName(EventInfo eventInfo) { String captureVariableName = null; if (captureOutput && StringUtils.isEmpty(captureVariableName = this.captureVariableName.getText(eventInfo))) { throw new IllegalArgumentException("Invalid variable name"); @@ -142,7 +132,7 @@ private String getVariableName(IEventInfo eventInfo) { return captureVariableName; } - private int getFailAfter(IEventInfo eventInfo) { + private int getFailAfter(EventInfo eventInfo) { int failAfter = 0; if (waitForCompletion && (failAfter = this.failAfter.getInt(eventInfo)) <= 0) { throw new IllegalArgumentException("Invalid wait limit value"); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunRules.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunRules.java index 035d604..afe6584 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunRules.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunRules.java @@ -4,24 +4,29 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.messages.IEventInfo; -import synfron.reshaper.burp.core.rules.Rule; -import synfron.reshaper.burp.core.rules.RuleOperationType; -import synfron.reshaper.burp.core.rules.RuleResponse; -import synfron.reshaper.burp.core.rules.RulesEngine; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpEventInfo; +import synfron.reshaper.burp.core.rules.*; import java.util.stream.Stream; -public class ThenRunRules extends Then { - private int cacheVersion; +public class ThenRunRules extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { + + private transient int cacheVersion; private transient Rule ruleCache = null; @Getter @Setter private boolean runSingle = true; @Getter @Setter private String ruleName; - public RuleResponse perform(IEventInfo eventInfo) { - RulesEngine rulesEngine = BurpExtender.getConnector().getRulesEngine(); + private RulesEngine getRulesEngine(EventInfo eventInfo) { + return (eventInfo instanceof HttpEventInfo) ? + BurpExtender.getHttpConnector().getRulesEngine() : + BurpExtender.getWebSocketConnector().getRulesEngine(); + } + + public RuleResponse perform(EventInfo eventInfo) { + RulesEngine rulesEngine = getRulesEngine(eventInfo); RuleResponse ruleResponse; if (runSingle) { Rule rule; diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunScript.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunScript.java index 1f55dc0..973bfe8 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunScript.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenRunScript.java @@ -2,20 +2,22 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.thens.entities.script.Dispatcher; import synfron.reshaper.burp.core.rules.thens.entities.script.Environment; -public class ThenRunScript extends Then { +public class ThenRunScript extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private String script; @Getter @Setter private int maxExecutionSeconds = 10; - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = false; RuleResponse ruleResponse = RuleResponse.Continue; try { diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSaveFile.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSaveFile.java index 11a9264..6d36a5f 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSaveFile.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSaveFile.java @@ -6,7 +6,9 @@ import org.apache.commons.lang3.tuple.Pair; import synfron.reshaper.burp.core.exceptions.WrappedException; import synfron.reshaper.burp.core.messages.Encoder; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.thens.entities.savefile.FileExistsAction; @@ -20,7 +22,7 @@ import java.nio.file.Paths; import java.util.List; -public class ThenSaveFile extends Then { +public class ThenSaveFile extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableString filePath; @Getter @Setter @@ -31,7 +33,7 @@ public class ThenSaveFile extends Then { private FileExistsAction fileExistsAction = FileExistsAction.Overwrite; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = true; String filePathValue = null; String textValue = null; diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendMessage.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendMessage.java new file mode 100644 index 0000000..a7b6695 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendMessage.java @@ -0,0 +1,39 @@ +package synfron.reshaper.burp.core.rules.thens; + +import lombok.Getter; +import lombok.Setter; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.WebSocketDataDirection; +import synfron.reshaper.burp.core.messages.WebSocketEventInfo; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; +import synfron.reshaper.burp.core.rules.RuleOperationType; +import synfron.reshaper.burp.core.rules.RuleResponse; +import synfron.reshaper.burp.core.vars.VariableString; + +public class ThenSendMessage extends Then implements IWebSocketRuleOperation { + + @Getter + @Setter + private WebSocketDataDirection dataDirection = WebSocketDataDirection.Server; + @Getter + @Setter + private VariableString message; + + @Override + public RuleResponse perform(EventInfo eventInfo) { + boolean hasError = true; + String value = null; + try { + ((WebSocketEventInfo)eventInfo).getMessageSender().accept(dataDirection, value = message.getText(eventInfo)); + hasError = false; + } finally { + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue(this, hasError, value); + } + return RuleResponse.Continue; + } + + @Override + public RuleOperationType getType() { + return ThenType.SendMessage; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendRequest.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendRequest.java index 0d4a8be..e4de302 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendRequest.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendRequest.java @@ -1,16 +1,18 @@ package synfron.reshaper.burp.core.rules.thens; import burp.BurpExtender; +import burp.api.montoya.http.HttpMode; +import burp.api.montoya.http.message.responses.HttpResponse; import lombok.Getter; import lombok.Setter; -import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.events.Event; import synfron.reshaper.burp.core.exceptions.WrappedException; -import synfron.reshaper.burp.core.messages.DataDirection; import synfron.reshaper.burp.core.messages.EventInfo; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.HttpEventInfo; +import synfron.reshaper.burp.core.messages.entities.http.HttpResponseMessage; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.utils.Log; @@ -22,7 +24,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; -public class ThenSendRequest extends Then { +public class ThenSendRequest extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableString request; @Getter @Setter @@ -51,21 +53,21 @@ public class ThenSendRequest extends Then { private VariableString captureVariableName; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = false; boolean failed = false; boolean complete = false; String output = null; - int exitCode = 0; + int statusCode = 0; String captureVariableName = null; try { int failAfterInMilliseconds = waitForCompletion ? getFailAfter(eventInfo) : 0; captureVariableName = getVariableName(eventInfo); ExecutorService executor = Executors.newSingleThreadExecutor(); - AtomicReference response = new AtomicReference<>(); + AtomicReference response = new AtomicReference<>(); executor.submit(() -> { try { - EventInfo newEventInfo = new EventInfo(eventInfo); + HttpEventInfo newEventInfo = new HttpEventInfo(eventInfo); boolean useHttps = !StringUtils.equalsIgnoreCase(newEventInfo.getHttpProtocol(), "http"); if (!VariableString.isEmpty(request)) { newEventInfo.setHttpRequestMessage(eventInfo.getEncoder().encode(this.request.getText(eventInfo))); @@ -90,13 +92,11 @@ public RuleResponse perform(IEventInfo eventInfo) { )); } - byte[] responseBytes = BurpExtender.getCallbacks().makeHttpRequest( - newEventInfo.getDestinationAddress(), - newEventInfo.getDestinationPort(), - useHttps, - newEventInfo.getHttpRequestMessage().getValue() - ); - response.set(responseBytes); + HttpResponse httpResponse = BurpExtender.getApi().http().issueRequest( + newEventInfo.asHttpRequest(), + HttpMode.AUTO + ).httpResponse(); + response.set(httpResponse); } catch (Exception e) { Log.get().withMessage("Failure sending request").withException(e).logErr(); } finally { @@ -108,14 +108,14 @@ public RuleResponse perform(IEventInfo eventInfo) { if (complete) { executor.shutdownNow(); } - byte[] responseBytes = response.get(); - exitCode = complete && failOnErrorStatusCode && ArrayUtils.isNotEmpty(responseBytes) ? - (int) BurpExtender.getCallbacks().getHelpers().analyzeResponse(response.get()).getStatusCode() : + HttpResponse httpResponse = response.get(); + statusCode = complete && failOnErrorStatusCode && httpResponse != null ? + httpResponse.statusCode() : 0; - failed = !complete || (failOnErrorStatusCode && (exitCode == 0 || (exitCode >= 400 && exitCode < 600))); + failed = !complete || (failOnErrorStatusCode && (statusCode == 0 || (statusCode >= 400 && statusCode < 600))); if (captureOutput && (!failed || captureAfterFailure)) { - output = response.get() != null ? BurpExtender.getCallbacks().getHelpers().bytesToString(response.get()) : ""; - setVariable(eventInfo, captureVariableName, output); + output = response.get() != null ? new HttpResponseMessage(response.get().asBytes().getBytes(), eventInfo.getEncoder()).getText() : ""; + setVariable(captureVariableSource, eventInfo, captureVariableName, output); } } } catch (InterruptedException e) { @@ -139,25 +139,13 @@ public RuleResponse perform(IEventInfo eventInfo) { Pair.of("captureVariableName", waitForCompletion && captureOutput ? captureVariableName : null), Pair.of("exceededWait", waitForCompletion ? !complete : null), Pair.of("failed", waitForCompletion ? failed : null), - Pair.of("exitCode", waitForCompletion ? exitCode : null) + Pair.of("exitCode", waitForCompletion ? statusCode : null) )); } return failed && breakAfterFailure ? RuleResponse.BreakRules : RuleResponse.Continue; } - private void setVariable(IEventInfo eventInfo, String variableName, String value) { - Variables variables = switch (captureVariableSource) { - case Event -> eventInfo.getVariables(); - case Global -> GlobalVariables.get(); - default -> null; - }; - if (variables != null) { - Variable variable = variables.add(variableName); - variable.setValue(value); - } - } - - private String getVariableName(IEventInfo eventInfo) { + private String getVariableName(EventInfo eventInfo) { String captureVariableName = null; if (captureOutput && StringUtils.isEmpty(captureVariableName = this.captureVariableName.getText(eventInfo))) { throw new IllegalArgumentException("Invalid variable name"); @@ -165,7 +153,7 @@ private String getVariableName(IEventInfo eventInfo) { return captureVariableName; } - private int getFailAfter(IEventInfo eventInfo) { + private int getFailAfter(EventInfo eventInfo) { int failAfter = 0; if (waitForCompletion && (failAfter = this.failAfter.getInt(eventInfo)) <= 0) { throw new IllegalArgumentException("Invalid wait limit value"); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendTo.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendTo.java index 977a76d..71eb5ab 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendTo.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSendTo.java @@ -1,30 +1,32 @@ package synfron.reshaper.burp.core.rules.thens; import burp.BurpExtender; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.http.HttpService; +import burp.api.montoya.http.message.requests.HttpRequest; import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import org.apache.commons.lang3.tuple.Pair; import synfron.reshaper.burp.core.exceptions.WrappedException; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.thens.entities.sendto.SendToOption; import synfron.reshaper.burp.core.utils.CollectionUtils; -import synfron.reshaper.burp.core.utils.ObjectUtils; -import synfron.reshaper.burp.core.utils.TextUtils; +import synfron.reshaper.burp.core.utils.Url; +import synfron.reshaper.burp.core.utils.UrlUtils; import synfron.reshaper.burp.core.vars.VariableString; -import java.awt.Desktop; +import java.awt.*; import java.io.IOException; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; import java.util.Arrays; -public class ThenSendTo extends Then { +public class ThenSendTo extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private SendToOption sendTo = SendToOption.Repeater; @@ -43,19 +45,18 @@ public class ThenSendTo extends Then { @Getter @Setter private VariableString url; - public RuleResponse perform(IEventInfo eventInfo) + public RuleResponse perform(EventInfo eventInfo) { switch (sendTo) { case Comparer -> sendToComparer(eventInfo); case Intruder -> sendToIntruder(eventInfo); case Repeater -> sendToRepeater(eventInfo); - case Spider -> sendToSpider(eventInfo); case Browser -> sendToBrowser(eventInfo); } return RuleResponse.Continue; } - private void sendToIntruder(IEventInfo eventInfo) { + private void sendToIntruder(EventInfo eventInfo) { String host = null; int port = 0; boolean isHttps = false; @@ -81,7 +82,7 @@ private void sendToIntruder(IEventInfo eventInfo) { isHttps = StringUtils.equalsIgnoreCase(eventInfo.getHttpProtocol(), "https"); request = eventInfo.getHttpRequestMessage().getValue(); } - BurpExtender.getCallbacks().sendToIntruder(host, port, isHttps, request); + BurpExtender.getApi().intruder().sendToIntruder(HttpRequest.httpRequest(HttpService.httpService(host, port, isHttps), ByteArray.byteArray(request))); } catch (Exception e) { hasError = true; throw e; @@ -96,7 +97,7 @@ private void sendToIntruder(IEventInfo eventInfo) { } } - private void sendToRepeater(IEventInfo eventInfo) { + private void sendToRepeater(EventInfo eventInfo) { String host = null; int port = 0; boolean isHttps = false; @@ -122,7 +123,7 @@ private void sendToRepeater(IEventInfo eventInfo) { isHttps = StringUtils.equalsIgnoreCase(eventInfo.getHttpProtocol(), "https"); request = eventInfo.getHttpRequestMessage().getValue(); } - BurpExtender.getCallbacks().sendToRepeater(host, port, isHttps, request, null); + BurpExtender.getApi().repeater().sendToRepeater(HttpRequest.httpRequest(HttpService.httpService(host, port, isHttps), ByteArray.byteArray(request))); } catch (Exception e) { hasError = true; throw e; @@ -137,7 +138,7 @@ private void sendToRepeater(IEventInfo eventInfo) { } } - private void sendToComparer(IEventInfo eventInfo) { + private void sendToComparer(EventInfo eventInfo) { byte[] data = null; boolean hasError = false; try { @@ -151,7 +152,7 @@ private void sendToComparer(IEventInfo eventInfo) { } else { data = eventInfo.getHttpRequestMessage().getValue(); } - BurpExtender.getCallbacks().sendToComparer(data); + BurpExtender.getApi().comparer().sendToComparer(ByteArray.byteArray(data)); } catch (Exception e) { hasError = true; throw e; @@ -163,43 +164,14 @@ private void sendToComparer(IEventInfo eventInfo) { } } - private void sendToSpider(IEventInfo eventInfo) { - URL url = null; + private void sendToBrowser(EventInfo eventInfo) { + Url url = null; boolean hasError = false; try { if (overrideDefaults && this.url != null && !this.url.isEmpty()) { - url = new URL(this.url.getText(eventInfo)); + url = new Url(this.url.getText(eventInfo)); } else { - url = ObjectUtils.getUrl( - eventInfo.getHttpProtocol().toLowerCase(), - eventInfo.getDestinationAddress(), - eventInfo.getDestinationPort(), - eventInfo.getHttpRequestMessage().getStatusLine().getUrl().getValue() - ); - } - BurpExtender.getCallbacks().sendToSpider(url); - } catch (MalformedURLException e) { - hasError = true; - throw new WrappedException(e); - } catch (Exception e) { - hasError = true; - throw e; - } finally { - if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logProperties(this, hasError, Arrays.asList( - Pair.of("sendTo", sendTo), - Pair.of("url", url) - )); - } - } - - private void sendToBrowser(IEventInfo eventInfo) { - URL url = null; - boolean hasError = false; - try { - if (overrideDefaults && this.url != null && !this.url.isEmpty()) { - url = new URL(this.url.getText(eventInfo)); - } else { - url = ObjectUtils.getUrl( + url = UrlUtils.getUrl( eventInfo.getHttpProtocol().toLowerCase(), eventInfo.getDestinationAddress(), eventInfo.getDestinationPort(), @@ -207,7 +179,7 @@ private void sendToBrowser(IEventInfo eventInfo) { ); } openBrowser(url.toURI()); - } catch (URISyntaxException | IOException e) { + } catch (IOException e) { hasError = true; throw new WrappedException(e); } catch (Exception e) { diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSet.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSet.java index a453edd..f738ed1 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSet.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSet.java @@ -3,10 +3,7 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.messages.MessageValue; -import synfron.reshaper.burp.core.messages.MessageValueHandler; -import synfron.reshaper.burp.core.messages.MessageValueType; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.*; import synfron.reshaper.burp.core.utils.GetItemPlacement; import synfron.reshaper.burp.core.utils.TextUtils; import synfron.reshaper.burp.core.vars.VariableString; @@ -15,7 +12,7 @@ public abstract class ThenSet> extends Then { @Getter @Setter private boolean useMessageValue = true; @Getter @Setter - private MessageValue sourceMessageValue = MessageValue.HttpRequestBody; + private MessageValue sourceMessageValue; @Getter @Setter private VariableString sourceIdentifier; @Getter @Setter @@ -37,12 +34,12 @@ public abstract class ThenSet> extends Then { @Getter @Setter protected VariableString destinationMessageValuePath; - private String getValue(IEventInfo eventInfo) + private String getValue(EventInfo eventInfo) { return MessageValueHandler.getValue(eventInfo, sourceMessageValue, sourceIdentifier, sourceIdentifierPlacement); } - protected String getReplacementValue(IEventInfo eventInfo) + protected String getReplacementValue(EventInfo eventInfo) { String text = ""; if (useMessageValue) diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetEncoding.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetEncoding.java index ca97698..09863e4 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetEncoding.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetEncoding.java @@ -1,20 +1,21 @@ package synfron.reshaper.burp.core.rules.thens; -import burp.BurpExtender; import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.vars.VariableString; -public class ThenSetEncoding extends Then { +public class ThenSetEncoding extends Then implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableString encoding; @Override - public RuleResponse perform(IEventInfo eventInfo) { + public RuleResponse perform(EventInfo eventInfo) { boolean hasError = false; String encodingValue = encoding.getText(eventInfo); try { diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetEventDirection.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetEventDirection.java index 796b59d..6b1f01e 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetEventDirection.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetEventDirection.java @@ -2,19 +2,21 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.DataDirection; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpDataDirection; +import synfron.reshaper.burp.core.messages.HttpEventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; -public class ThenSetEventDirection extends Then { +public class ThenSetEventDirection extends Then implements IHttpRuleOperation { @Getter @Setter - private DataDirection dataDirection = DataDirection.Request; + private HttpDataDirection dataDirection = HttpDataDirection.Request; @Override - public RuleResponse perform(IEventInfo eventInfo) { - eventInfo.setDataDirection(dataDirection); + public RuleResponse perform(EventInfo eventInfo) { + ((HttpEventInfo)eventInfo).setDataDirection(dataDirection); if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue(this, false, dataDirection); return RuleResponse.Continue; } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetValue.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetValue.java index 61056cf..f465c5d 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetValue.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetValue.java @@ -3,10 +3,9 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.IEventInfo; -import synfron.reshaper.burp.core.messages.MessageValue; -import synfron.reshaper.burp.core.messages.MessageValueHandler; -import synfron.reshaper.burp.core.messages.MessageValueType; +import synfron.reshaper.burp.core.messages.*; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.utils.IItemPlacement; @@ -17,9 +16,9 @@ import java.util.Arrays; import java.util.Collections; -public class ThenSetValue extends ThenSet { +public class ThenSetValue extends ThenSet implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter - private MessageValue destinationMessageValue = MessageValue.HttpRequestBody; + private MessageValue destinationMessageValue; @Getter @Setter private VariableString destinationIdentifier; @Getter @Setter @@ -29,7 +28,7 @@ public ThenSetValue() { setUseMessageValue(false); } - public RuleResponse perform(IEventInfo eventInfo) + public RuleResponse perform(EventInfo eventInfo) { try { String replacementText = getReplacementValue(eventInfo); @@ -40,7 +39,7 @@ public RuleResponse perform(IEventInfo eventInfo) return RuleResponse.Continue; } - private void setValue(IEventInfo eventInfo, String replacementText) + private void setValue(EventInfo eventInfo, String replacementText) { if (destinationMessageValueType != MessageValueType.Text) { String fullText = MessageValueHandler.getValue( diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetVariable.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetVariable.java index 172c960..d6d9563 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetVariable.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenSetVariable.java @@ -3,8 +3,10 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; import synfron.reshaper.burp.core.messages.MessageValueType; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.utils.TextUtils; @@ -13,14 +15,14 @@ import java.util.Arrays; import java.util.Collections; -public class ThenSetVariable extends ThenSet { +public class ThenSetVariable extends ThenSet implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableSource targetSource = VariableSource.Global; @Getter @Setter private VariableString variableName; - public RuleResponse perform(IEventInfo eventInfo) + public RuleResponse perform(EventInfo eventInfo) { try { String replacementText = getReplacementValue(eventInfo); @@ -31,13 +33,9 @@ public RuleResponse perform(IEventInfo eventInfo) return RuleResponse.Continue; } - private void setValue(IEventInfo eventInfo, String replacementText) + private void setValue(EventInfo eventInfo, String replacementText) { - Variables variables = switch (targetSource) { - case Event -> eventInfo.getVariables(); - case Global -> GlobalVariables.get(); - default -> null; - }; + Variables variables = getVariables(targetSource, eventInfo); if (variables != null) { Variable variable = variables.add(variableName.getText(eventInfo)); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java index 32d134a..bd8a30b 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/ThenType.java @@ -28,7 +28,9 @@ public class ThenType> extends RuleOperationType { public static final ThenType BuildHttpMessage = new ThenType<>("Build HTTP Message", ThenBuildHttpMessage.class); public static final ThenType ParseHttpMessage = new ThenType<>("Parse HTTP Message", ThenParseHttpMessage.class); public static final ThenType SendRequest = new ThenType<>("Send Request", ThenSendRequest.class); + public static final ThenType SendMessage = new ThenType<>("Send Message", ThenSendMessage.class); public static final ThenType Drop = new ThenType<>("Drop", ThenDrop.class); + public static final ThenType Intercept = new ThenType<>("Intercept", ThenIntercept.class); private ThenType() { this(null, null); @@ -61,7 +63,9 @@ public static List> getTypes() { ParseHttpMessage, BuildHttpMessage, SendRequest, - Drop + SendMessage, + Drop, + Intercept ); } } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/buildhttpmessage/MessageValueSetter.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/buildhttpmessage/MessageValueSetter.java index 7f83116..dd916ea 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/buildhttpmessage/MessageValueSetter.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/buildhttpmessage/MessageValueSetter.java @@ -1,9 +1,8 @@ package synfron.reshaper.burp.core.rules.thens.entities.buildhttpmessage; import lombok.Data; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.messages.MessageValue; -import synfron.reshaper.burp.core.utils.GetItemPlacement; import synfron.reshaper.burp.core.utils.SetItemPlacement; import synfron.reshaper.burp.core.vars.VariableString; @@ -18,7 +17,7 @@ public class MessageValueSetter implements Serializable { public MessageValueSetter() {} - public MessageValueSetter(DataDirection dataDirection) { - destinationMessageValue = dataDirection == DataDirection.Request ? MessageValue.HttpRequestBody : MessageValue.HttpResponseBody; + public MessageValueSetter(HttpDataDirection dataDirection) { + destinationMessageValue = dataDirection == HttpDataDirection.Request ? MessageValue.HttpRequestBody : MessageValue.HttpResponseBody; } } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/parsehttpmessage/MessageValueGetter.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/parsehttpmessage/MessageValueGetter.java index 9fb887c..8000c6b 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/parsehttpmessage/MessageValueGetter.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/parsehttpmessage/MessageValueGetter.java @@ -1,10 +1,9 @@ package synfron.reshaper.burp.core.rules.thens.entities.parsehttpmessage; import lombok.Data; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.utils.GetItemPlacement; -import synfron.reshaper.burp.core.utils.SetItemPlacement; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.core.vars.VariableString; @@ -20,7 +19,7 @@ public class MessageValueGetter implements Serializable { public MessageValueGetter() {} - public MessageValueGetter(DataDirection dataDirection) { - sourceMessageValue = dataDirection == DataDirection.Request ? MessageValue.HttpRequestBody : MessageValue.HttpResponseBody; + public MessageValueGetter(HttpDataDirection dataDirection) { + sourceMessageValue = dataDirection == HttpDataDirection.Request ? MessageValue.HttpRequestBody : MessageValue.HttpResponseBody; } } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java index b9cd7f0..64aec0b 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/ReshaperObj.java @@ -4,9 +4,11 @@ import org.apache.commons.lang3.StringUtils; import org.mozilla.javascript.NativeJSON; import org.mozilla.javascript.NativeObject; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.EventInfo; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.messages.MessageValueHandler; +import synfron.reshaper.burp.core.messages.WebSocketEventInfo; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.thens.Then; @@ -36,7 +38,16 @@ public String getGlobalVariable(String name) { } public String getEventVariable(String name) { - return getVariable(((IEventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getVariables(), name); + return getVariable(((EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getVariables(), name); + } + + public String getSessionVariable(String name) { + EventInfo eventInfo = (EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"); + if (eventInfo instanceof WebSocketEventInfo) { + WebSocketEventInfo webSocketEventInfo = (WebSocketEventInfo) eventInfo; + return getVariable(webSocketEventInfo.getSessionVariables(), name); + } + return null; } private String getVariable(Variables variables, String name) { @@ -57,7 +68,18 @@ public void setEventVariable(String name, String value) { if (!VariableString.isValidVariableName(name)) { throw new IllegalArgumentException(String.format("Invalid variable name '%s'", name)); } - ((IEventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getVariables().add(name).setValue(value); + ((EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getVariables().add(name).setValue(value); + } + + public void setSessionVariable(String name, String value) { + if (!VariableString.isValidVariableName(name)) { + throw new IllegalArgumentException(String.format("Invalid variable name '%s'", name)); + } + EventInfo eventInfo = (EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"); + if (eventInfo instanceof WebSocketEventInfo) { + WebSocketEventInfo webSocketEventInfo = (WebSocketEventInfo) eventInfo; + webSocketEventInfo.getSessionVariables().add(name).setValue(value); + } } public void deleteGlobalVariable(String name) { @@ -65,23 +87,36 @@ public void deleteGlobalVariable(String name) { } public void deleteEventVariable(String name) { - ((IEventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getVariables().remove(name); + ((EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getVariables().remove(name); + } + + public void deleteSessionVariable(String name) { + EventInfo eventInfo = (EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"); + if (eventInfo instanceof WebSocketEventInfo) { + WebSocketEventInfo webSocketEventInfo = (WebSocketEventInfo) eventInfo; + webSocketEventInfo.getSessionVariables().remove(name); + } } } public static class EventObj { public List getMessageValueKeys() { - return Arrays.stream(MessageValue.values()).map(Enum::name).collect(Collectors.toList()); + EventInfo eventInfo = (EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"); + return Arrays.stream(MessageValue.values()) + .filter(value -> value.hasProtocolType(eventInfo.getProtocolType())) + .map(Enum::name) + .collect(Collectors.toList()); } public String getMessageValue(String key, String identifier) { MessageValue messageValue = EnumUtils.getEnumIgnoreCase(MessageValue.class, key); - if (messageValue == null) { + EventInfo eventInfo = (EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"); + if (messageValue == null || !messageValue.hasProtocolType(eventInfo.getProtocolType())) { throw new IllegalArgumentException(String.format("Invalid message value key: '%s'", key)); } return MessageValueHandler.getValue( - (IEventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"), + eventInfo, EnumUtils.getEnumIgnoreCase(MessageValue.class, key), VariableString.getAsVariableString(identifier, false), GetItemPlacement.Last @@ -90,11 +125,12 @@ public String getMessageValue(String key, String identifier) { public void setMessageValue(String key, String identifier, String value) { MessageValue messageValue = EnumUtils.getEnumIgnoreCase(MessageValue.class, key); - if (messageValue == null) { + EventInfo eventInfo = (EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"); + if (messageValue == null || !messageValue.hasProtocolType(eventInfo.getProtocolType())) { throw new IllegalArgumentException(String.format("Invalid message value key: '%s'", key)); } MessageValueHandler.setValue( - (IEventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"), + eventInfo, EnumUtils.getEnumIgnoreCase(MessageValue.class, key), VariableString.getAsVariableString(identifier, false), SetItemPlacement.Only, @@ -104,6 +140,7 @@ public void setMessageValue(String key, String identifier, String value) { public String runThen(String thenType, NativeObject thenData) { Dispatcher dispatcher = Dispatcher.getCurrent(); + EventInfo eventInfo = (EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo"); String adjustedThenTypeName = StringUtils.prependIfMissing(thenType, "Then"); Stream> supportedThenTypes = Stream.of( ThenType.Highlight, @@ -113,9 +150,11 @@ public String runThen(String thenType, NativeObject thenData) { ThenType.DeleteValue, ThenType.DeleteVariable, ThenType.Drop, + ThenType.Intercept, ThenType.Log, ThenType.ParseHttpMessage, ThenType.SendRequest, + ThenType.SendMessage, ThenType.SendTo, ThenType.SetEventDirection, ThenType.SetEncoding, @@ -123,6 +162,7 @@ public String runThen(String thenType, NativeObject thenData) { ThenType.SetVariable ); Class thenClass = supportedThenTypes + .filter(type -> eventInfo.getProtocolType().accepts(ProtocolType.fromRuleOperationType(type.getType()))) .filter(type -> type.getType().getSimpleName().equalsIgnoreCase(adjustedThenTypeName)) .map(RuleOperationType::getType) .findFirst() @@ -136,7 +176,7 @@ public String runThen(String thenType, NativeObject thenData) { null ).toString(); Then then = (Then)Serializer.deserialize(thenDataJson, thenClass); - return then.perform((IEventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).toString(); + return then.perform(eventInfo).toString(); } public void setRuleResponse(String ruleResponse) { diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/XmlHttpRequestObj.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/XmlHttpRequestObj.java index 264d80f..52f790e 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/XmlHttpRequestObj.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/script/XmlHttpRequestObj.java @@ -1,6 +1,10 @@ package synfron.reshaper.burp.core.rules.thens.entities.script; import burp.BurpExtender; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.http.HttpService; +import burp.api.montoya.http.message.requests.HttpRequest; +import burp.api.montoya.http.message.responses.HttpResponse; import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.StringUtils; @@ -9,11 +13,11 @@ import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.NativeJavaObject; -import synfron.reshaper.burp.core.messages.IEventInfo; import synfron.reshaper.burp.core.messages.Encoder; -import synfron.reshaper.burp.core.messages.entities.HttpRequestMessage; -import synfron.reshaper.burp.core.messages.entities.HttpResponseMessage; -import synfron.reshaper.burp.core.messages.entities.HttpResponseStatusLine; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.entities.http.HttpRequestMessage; +import synfron.reshaper.burp.core.messages.entities.http.HttpResponseMessage; +import synfron.reshaper.burp.core.messages.entities.http.HttpResponseStatusLine; import synfron.reshaper.burp.core.utils.CollectionUtils; import synfron.reshaper.burp.core.utils.GetItemPlacement; import synfron.reshaper.burp.core.utils.SetItemPlacement; @@ -77,7 +81,7 @@ public void open(String method, String url, boolean async) throws URISyntaxExcep uriBuilder.setParameters(inputUriBuilder.getQueryParams()); uriBuilder.setFragment(inputUriBuilder.getFragment()); String request = String.format(requestTemplate, method, uriBuilder, requestUrl.getAuthority()); - Encoder encoder = ((IEventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getEncoder(); + Encoder encoder = ((EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getEncoder(); requestMessage = new HttpRequestMessage(encoder.encode(request), encoder); setReadyState(OPENED); } @@ -143,22 +147,24 @@ private void doSend(String body, Dispatcher.Task timeoutTask) { if (!Thread.interrupted()) { try { HttpRequestMessage requestMessage = this.requestMessage; - Encoder encoder = ((IEventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getEncoder(); + Encoder encoder = ((EventInfo)Dispatcher.getCurrent().getDataBag().get("eventInfo")).getEncoder(); if (StringUtils.isNotEmpty(body)) { requestMessage = new HttpRequestMessage(requestMessage.getValue(), encoder); requestMessage.setBody(body); } boolean useHttps = !StringUtils.equalsIgnoreCase(requestUrl.getScheme(), "http"); - byte[] response = BurpExtender.getCallbacks().makeHttpRequest( - requestUrl.getHost(), - requestUrl.getPort() > 0 ? requestUrl.getPort() : (useHttps ? 443 : 80), - useHttps, - requestMessage.getValue() - ); + HttpResponse response = BurpExtender.getApi().http().issueRequest( + HttpRequest.httpRequest(ByteArray.byteArray(requestMessage.getValue())) + .withService(HttpService.httpService( + requestUrl.getHost(), + requestUrl.getPort() > 0 ? requestUrl.getPort() : (useHttps ? 443 : 80), + useHttps + )) + ).httpResponse(); if (!dispatcher.isTimeoutReach() && this.executor == executor) { this.executor = null; dispatcher.execute(context -> { - if (response != null && response.length != 0) { + if (response != null) { responseURL = requestUrl.toString(); responseMessage = new HttpResponseMessage(response, encoder); setReadyState(DONE); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/sendto/SendToOption.java b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/sendto/SendToOption.java index efde53b..5e08742 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/sendto/SendToOption.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/thens/entities/sendto/SendToOption.java @@ -4,6 +4,6 @@ public enum SendToOption { Comparer, Intruder, Repeater, - Spider, + Spider, // Unused Browser } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/When.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/When.java index b02ae7d..d03c01f 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/When.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/When.java @@ -4,8 +4,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; -import synfron.reshaper.burp.core.messages.MimeType; +import synfron.reshaper.burp.core.messages.EventInfo; import synfron.reshaper.burp.core.rules.IRuleOperation; import synfron.reshaper.burp.core.utils.Serializer; @@ -27,10 +26,10 @@ public abstract class When> implements IRuleOperation { @Getter @Setter private boolean useOrCondition; - public abstract boolean isMatch(IEventInfo eventInfo); + public abstract boolean isMatch(EventInfo eventInfo); @SuppressWarnings("unchecked") - public T copy() { - return (T) Serializer.copy(this); + public IRuleOperation copy() { + return Serializer.copy(this); } } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenContentType.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenContentType.java index 46f2e82..ac0659c 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenContentType.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenContentType.java @@ -3,17 +3,19 @@ import lombok.Getter; import lombok.Setter; import synfron.reshaper.burp.core.messages.ContentType; -import synfron.reshaper.burp.core.messages.IEventInfo; -import synfron.reshaper.burp.core.messages.ContentType; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.MatchType; import synfron.reshaper.burp.core.rules.RuleOperationType; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; -public class WhenContentType extends When { +public class WhenContentType extends When implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private ContentType contentType = ContentType.Json; @Override - public boolean isMatch(IEventInfo eventInfo) { + public boolean isMatch(EventInfo eventInfo) { ContentType eventContentType = eventInfo.getHttpRequestMessage().getContentType(); boolean isMatch = eventContentType != null && this.contentType.hasFlags(eventContentType); if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logCompare(this, null, MatchType.Contains, contentType, eventContentType, isMatch); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenEventDirection.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenEventDirection.java index a626599..9be16bd 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenEventDirection.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenEventDirection.java @@ -2,19 +2,19 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.DataDirection; -import synfron.reshaper.burp.core.messages.IEventInfo; -import synfron.reshaper.burp.core.rules.MatchType; -import synfron.reshaper.burp.core.rules.RuleOperationType; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpDataDirection; +import synfron.reshaper.burp.core.messages.HttpEventInfo; +import synfron.reshaper.burp.core.rules.*; -public class WhenEventDirection extends When { +public class WhenEventDirection extends When implements IHttpRuleOperation { @Getter @Setter - private DataDirection dataDirection = DataDirection.Request; + private HttpDataDirection dataDirection = HttpDataDirection.Request; @Override - public boolean isMatch(IEventInfo eventInfo) { - boolean isMatch = eventInfo.getDataDirection() == dataDirection; - if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logCompare(this, null, MatchType.Equals, dataDirection, eventInfo.getDataDirection(), isMatch); + public boolean isMatch(EventInfo eventInfo) { + boolean isMatch = ((HttpEventInfo)eventInfo).getDataDirection() == dataDirection; + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logCompare(this, null, MatchType.Equals, dataDirection, ((HttpEventInfo)eventInfo).getDataDirection(), isMatch); return isMatch; } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenFromTool.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenFromTool.java index 6da1c25..4b96086 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenFromTool.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenFromTool.java @@ -3,17 +3,19 @@ import lombok.Getter; import lombok.Setter; import synfron.reshaper.burp.core.BurpTool; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.MatchType; import synfron.reshaper.burp.core.rules.RuleOperationType; -public class WhenFromTool extends When { +public class WhenFromTool extends When implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private BurpTool tool = BurpTool.Proxy; @Override - public boolean isMatch(IEventInfo eventInfo) { + public boolean isMatch(EventInfo eventInfo) { boolean isMatch = eventInfo.getBurpTool() == tool; if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logCompare(this, null, MatchType.Equals, tool, eventInfo.getBurpTool(), isMatch); return isMatch; diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenHasEntity.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenHasEntity.java index 2a65ddf..8913a53 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenHasEntity.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenHasEntity.java @@ -3,20 +3,24 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpEventInfo; import synfron.reshaper.burp.core.messages.MessageValue; +import synfron.reshaper.burp.core.messages.WebSocketEventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.vars.VariableString; -public class WhenHasEntity extends When { +public class WhenHasEntity extends When implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter - private MessageValue messageValue = MessageValue.HttpRequestBody; + private MessageValue messageValue; @Getter @Setter private VariableString identifier; @Override - public boolean isMatch(IEventInfo eventInfo) + public boolean isMatch(EventInfo eventInfo) { boolean matches = false; try { @@ -26,21 +30,22 @@ public boolean isMatch(IEventInfo eventInfo) case HttpRequestMethod -> eventInfo.getHttpRequestMessage().getStatusLine().getMethod().length() > 0; case HttpRequestUri, Url -> eventInfo.getHttpRequestMessage().getStatusLine().getUrl().getValue().length() > 0; case HttpRequestStatusLine -> eventInfo.getHttpRequestMessage().getStatusLine().getValue().length() > 0; - case HttpResponseMessage -> eventInfo.getHttpResponseMessage().getValue().length > 0; - case HttpResponseStatusLine -> eventInfo.getHttpResponseMessage().getStatusLine().getValue().length() > 0; - case HttpResponseStatusCode -> eventInfo.getHttpResponseMessage().getStatusLine().getCode().length() > 0; - case HttpResponseStatusMessage -> eventInfo.getHttpResponseMessage().getStatusLine().getMessage().length() > 0; + case HttpResponseMessage -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getValue().length > 0; + case HttpResponseStatusLine -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getStatusLine().getValue().length() > 0; + case HttpResponseStatusCode -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getStatusLine().getCode().length() > 0; + case HttpResponseStatusMessage -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getStatusLine().getMessage().length() > 0; case HttpRequestBody -> eventInfo.getHttpRequestMessage().getBody().hasValue(); - case HttpResponseBody -> eventInfo.getHttpResponseMessage().getBody().hasValue(); + case HttpResponseBody -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getBody().hasValue(); case HttpRequestHeaders -> eventInfo.getHttpRequestMessage().getHeaders().getCount() > 0; - case HttpResponseHeaders -> eventInfo.getHttpResponseMessage().getHeaders().getCount() > 0; + case HttpResponseHeaders -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getHeaders().getCount() > 0; case HttpRequestHeader -> eventInfo.getHttpRequestMessage().getHeaders().contains(identifier.getText(eventInfo)); - case HttpResponseHeader -> eventInfo.getHttpResponseMessage().getHeaders().contains(identifier.getText(eventInfo)); + case HttpResponseHeader -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getHeaders().contains(identifier.getText(eventInfo)); case HttpRequestCookie -> eventInfo.getHttpRequestMessage().getHeaders().getCookies().contains(identifier.getText(eventInfo)); - case HttpResponseCookie -> eventInfo.getHttpResponseMessage().getHeaders().getCookies().contains(identifier.getText(eventInfo)); + case HttpResponseCookie -> ((HttpEventInfo)eventInfo).getHttpResponseMessage().getHeaders().getCookies().contains(identifier.getText(eventInfo)); case HttpRequestUriPath -> StringUtils.isNotEmpty(eventInfo.getHttpRequestMessage().getStatusLine().getUrl().getPath()); case HttpRequestUriQueryParameters -> StringUtils.isNotEmpty(eventInfo.getHttpRequestMessage().getStatusLine().getUrl().getQueryParametersText()); case HttpRequestUriQueryParameter -> eventInfo.getHttpRequestMessage().getStatusLine().getUrl().getQueryParams().hasQueryParameter(identifier.getText(eventInfo)); + case WebSocketMessage -> eventInfo instanceof WebSocketEventInfo; }; } catch (Exception ignored) { } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenInScope.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenInScope.java index 49b86a0..ac2bf1d 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenInScope.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenInScope.java @@ -3,14 +3,13 @@ import burp.BurpExtender; import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.vars.VariableString; -import java.net.MalformedURLException; -import java.net.URL; - -public class WhenInScope extends When { +public class WhenInScope extends When implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @@ -18,11 +17,11 @@ public class WhenInScope extends When { private VariableString url; @Override - public boolean isMatch(IEventInfo eventInfo) { + public boolean isMatch(EventInfo eventInfo) { boolean isMatch = false; String url = VariableString.getTextOrDefault(eventInfo, this.url, eventInfo.getUrl()); try { - isMatch = BurpExtender.getCallbacks().isInScope(new URL(url)); + isMatch = BurpExtender.getApi().scope().isInScope(url); } catch (Exception ignored) { } if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logValue(this, isMatch, url); diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMatchesText.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMatchesText.java index 814f1ab..cc2107c 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMatchesText.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMatchesText.java @@ -2,11 +2,11 @@ import lombok.Getter; import lombok.Setter; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.IEventInfo; -import synfron.reshaper.burp.core.messages.MessageValue; -import synfron.reshaper.burp.core.messages.MessageValueHandler; -import synfron.reshaper.burp.core.messages.MessageValueType; +import synfron.reshaper.burp.core.messages.*; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.MatchType; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.utils.GetItemPlacement; @@ -15,7 +15,7 @@ import java.util.Arrays; -public class WhenMatchesText extends When { +public class WhenMatchesText extends When implements IHttpRuleOperation, IWebSocketRuleOperation { @Getter @Setter private VariableString identifier; @@ -30,7 +30,7 @@ public class WhenMatchesText extends When { private VariableString matchText; @Getter @Setter - private MessageValue messageValue = MessageValue.HttpRequestBody; + private MessageValue messageValue; @Getter @Setter private MessageValueType messageValueType = MessageValueType.Text; @@ -42,10 +42,13 @@ public class WhenMatchesText extends When { private MatchType matchType = MatchType.Equals; @Getter @Setter + private boolean ignoreCase = false; + @Getter + @Setter public boolean useMessageValue = true; @Override - public boolean isMatch(IEventInfo eventInfo) { + public boolean isMatch(EventInfo eventInfo) { boolean isMatch = false; String sourceText = null; String matchText = null; @@ -57,11 +60,11 @@ public boolean isMatch(IEventInfo eventInfo) { matchText = this.matchText.getText(eventInfo); isMatch = switch (matchType) { - case BeginsWith -> sourceText.startsWith(matchText); - case EndsWith -> sourceText.endsWith(matchText); - case Contains -> sourceText.contains(matchText); - case Equals -> sourceText.equals(matchText); - case Regex -> TextUtils.isMatch(sourceText, matchText); + case BeginsWith -> ignoreCase ? StringUtils.startsWithIgnoreCase(sourceText, matchText) : StringUtils.startsWith(sourceText, matchText); + case EndsWith -> ignoreCase ? StringUtils.endsWithIgnoreCase(sourceText, matchText) : StringUtils.endsWith(sourceText, matchText); + case Contains -> ignoreCase ? StringUtils.containsIgnoreCase(sourceText, matchText) : StringUtils.contains(sourceText, matchText); + case Equals -> ignoreCase ? StringUtils.equalsIgnoreCase(sourceText, matchText) : StringUtils.equals(sourceText, matchText); + case Regex -> TextUtils.isMatch(sourceText, matchText, ignoreCase); }; } catch (Exception ignored) { } @@ -69,13 +72,14 @@ public boolean isMatch(IEventInfo eventInfo) { this, useMessageValue ? Arrays.asList( Pair.of("messageValue", messageValue), Pair.of("identifier", messageValue.isIdentifierRequired() ? VariableString.getTextOrDefault(eventInfo, identifier, null) : null), - Pair.of("identifierPlacement", messageValue.isIdentifierRequired() ? identifierPlacement : null) + Pair.of("identifierPlacement", messageValue.isIdentifierRequired() ? identifierPlacement : null), + Pair.of("ignoreCase", ignoreCase) ) : null, matchType, matchText, sourceText, isMatch ); return isMatch; } - private String getPathValue(String value, IEventInfo eventInfo) { + private String getPathValue(String value, EventInfo eventInfo) { if (messageValueType != MessageValueType.Text && messageValuePath != null) { switch (messageValueType) { diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMessageType.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMessageType.java new file mode 100644 index 0000000..b3080b8 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMessageType.java @@ -0,0 +1,27 @@ +package synfron.reshaper.burp.core.rules.whens; + +import lombok.Getter; +import lombok.Setter; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.WebSocketMessageType; +import synfron.reshaper.burp.core.messages.WebSocketEventInfo; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; +import synfron.reshaper.burp.core.rules.MatchType; +import synfron.reshaper.burp.core.rules.RuleOperationType; + +public class WhenMessageType extends When implements IWebSocketRuleOperation { + @Getter @Setter + private WebSocketMessageType messageType = WebSocketMessageType.Text; + + @Override + public boolean isMatch(EventInfo eventInfo) { + boolean isMatch = ((WebSocketEventInfo)eventInfo).getMessageType() == messageType; + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logCompare(this, null, MatchType.Equals, messageType, ((WebSocketEventInfo)eventInfo).getMessageType(), isMatch); + return isMatch; + } + + @Override + public RuleOperationType getType() { + return WhenType.MessageType; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMimeType.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMimeType.java index 068eee4..0d4134c 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMimeType.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenMimeType.java @@ -2,19 +2,20 @@ import lombok.Getter; import lombok.Setter; -import synfron.reshaper.burp.core.messages.DataDirection; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpEventInfo; import synfron.reshaper.burp.core.messages.MimeType; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; import synfron.reshaper.burp.core.rules.MatchType; import synfron.reshaper.burp.core.rules.RuleOperationType; -public class WhenMimeType extends When { +public class WhenMimeType extends When implements IHttpRuleOperation { @Getter @Setter private MimeType mimeType = MimeType.Html; @Override - public boolean isMatch(IEventInfo eventInfo) { - MimeType eventMimeType = eventInfo.getHttpResponseMessage().getMimeType(); + public boolean isMatch(EventInfo eventInfo) { + MimeType eventMimeType = ((HttpEventInfo)eventInfo).getHttpResponseMessage().getMimeType(); boolean isMatch = eventMimeType != null && this.mimeType.hasFlags(eventMimeType); if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logCompare(this, null, MatchType.Contains, mimeType, eventMimeType, isMatch); return isMatch; diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenProxyName.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenProxyName.java index 2e55568..81956ff 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenProxyName.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenProxyName.java @@ -3,18 +3,20 @@ import lombok.Getter; import lombok.Setter; import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.EventInfo; +import synfron.reshaper.burp.core.messages.HttpEventInfo; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; import synfron.reshaper.burp.core.rules.MatchType; import synfron.reshaper.burp.core.rules.RuleOperationType; -public class WhenProxyName extends When { +public class WhenProxyName extends When implements IHttpRuleOperation { @Getter @Setter private String proxyName; @Override - public boolean isMatch(IEventInfo eventInfo) { - boolean isMatch = StringUtils.equalsIgnoreCase(eventInfo.getProxyName(), proxyName); - if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logCompare(this, null, MatchType.Equals, proxyName, eventInfo.getProxyName(), isMatch); + public boolean isMatch(EventInfo eventInfo) { + boolean isMatch = StringUtils.equalsIgnoreCase(((HttpEventInfo)eventInfo).getProxyName(), proxyName); + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logCompare(this, null, MatchType.Equals, proxyName, ((HttpEventInfo)eventInfo).getProxyName(), isMatch); return isMatch; } diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenType.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenType.java index 1eaa07d..7bad002 100644 --- a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenType.java +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenType.java @@ -8,10 +8,12 @@ @EqualsAndHashCode(callSuper = true) public class WhenType> extends RuleOperationType { public static final WhenType EventDirection = new WhenType<>("Event Direction", WhenEventDirection.class); + public static final WhenType WebSocketEventDirection = new WhenType<>("Event Direction", WhenWebSocketEventDirection.class); public static final WhenType HasEntity = new WhenType<>("Has Entity", WhenHasEntity.class); public static final WhenType MatchesText = new WhenType<>("Matches Text", WhenMatchesText.class); - public static final WhenType ContentType = new WhenType<>("Content Type", WhenContentType.class); - public static final WhenType MimeType = new WhenType<>("MIME Type", WhenMimeType.class); + public static final WhenType ContentType = new WhenType<>("Request Content Type", WhenContentType.class); + public static final WhenType MimeType = new WhenType<>("Response MIME Type", WhenMimeType.class); + public static final WhenType MessageType = new WhenType<>("Message Type", WhenMessageType.class); public static final WhenType ProxyName = new WhenType<>("Proxy Name", WhenProxyName.class); public static final WhenType FromTool = new WhenType<>("From Tool", WhenFromTool.class); public static final WhenType InScope = new WhenType<>("In Scope", WhenInScope.class); @@ -27,10 +29,12 @@ private WhenType(String name, Class type) { public static List> getTypes() { return List.of( EventDirection, + WebSocketEventDirection, HasEntity, MatchesText, ContentType, MimeType, + MessageType, ProxyName, FromTool, InScope diff --git a/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenWebSocketEventDirection.java b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenWebSocketEventDirection.java new file mode 100644 index 0000000..165f9f4 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/rules/whens/WhenWebSocketEventDirection.java @@ -0,0 +1,25 @@ +package synfron.reshaper.burp.core.rules.whens; + +import lombok.Getter; +import lombok.Setter; +import synfron.reshaper.burp.core.messages.*; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; +import synfron.reshaper.burp.core.rules.MatchType; +import synfron.reshaper.burp.core.rules.RuleOperationType; + +public class WhenWebSocketEventDirection extends When implements IWebSocketRuleOperation { + @Getter @Setter + private WebSocketDataDirection dataDirection = WebSocketDataDirection.Server; + + @Override + public boolean isMatch(EventInfo eventInfo) { + boolean isMatch = ((WebSocketEventInfo)eventInfo).getDataDirection() == dataDirection; + if (eventInfo.getDiagnostics().isEnabled()) eventInfo.getDiagnostics().logCompare(this, null, MatchType.Equals, dataDirection, ((WebSocketEventInfo)eventInfo).getDataDirection(), isMatch); + return isMatch; + } + + @Override + public RuleOperationType getType() { + return WhenType.WebSocketEventDirection; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/settings/ExportSettings.java b/src/main/java/synfron/reshaper/burp/core/settings/ExportSettings.java index 8dc5638..f38c28e 100644 --- a/src/main/java/synfron/reshaper/burp/core/settings/ExportSettings.java +++ b/src/main/java/synfron/reshaper/burp/core/settings/ExportSettings.java @@ -10,5 +10,6 @@ @Data public class ExportSettings { private List rules = Collections.emptyList(); + private List webSocketRules = Collections.emptyList(); private List variables = Collections.emptyList(); } diff --git a/src/main/java/synfron/reshaper/burp/core/settings/GeneralSettings.java b/src/main/java/synfron/reshaper/burp/core/settings/GeneralSettings.java index 805c36f..4c78d6a 100644 --- a/src/main/java/synfron/reshaper/burp/core/settings/GeneralSettings.java +++ b/src/main/java/synfron/reshaper/burp/core/settings/GeneralSettings.java @@ -8,11 +8,11 @@ public class GeneralSettings { private boolean captureProxy = true; private boolean captureTarget; - private boolean captureSpider; private boolean captureScanner; private boolean captureRepeater; private boolean captureIntruder; private boolean captureExtender; + private boolean captureWebSockets = true; private boolean enableEventDiagnostics; private int diagnosticValueMaxLength = 200; private boolean enableSanityCheckWarnings = true; @@ -20,17 +20,18 @@ public class GeneralSettings { private int logTabCharacterLimit = 1000000; private String defaultEncoding = Encoder.getDefaultEncoderName(); private ImportMethod importMethod = ImportMethod.File; + private ExportMethod exportMethod = ExportMethod.Json; private String importUrl; public void importSettings(GeneralSettings other) { if (other != null) { this.captureProxy = other.captureProxy; this.captureTarget = other.captureTarget; - this.captureSpider = other.captureSpider; this.captureScanner = other.captureScanner; this.captureRepeater = other.captureRepeater; this.captureIntruder = other.captureIntruder; this.captureExtender = other.captureExtender; + this.captureWebSockets = other.captureWebSockets; this.enableEventDiagnostics = other.enableEventDiagnostics; this.diagnosticValueMaxLength = other.diagnosticValueMaxLength; this.enableSanityCheckWarnings = other.enableSanityCheckWarnings; @@ -46,11 +47,11 @@ public boolean isCapture(BurpTool burpTool) { case Proxy -> isCaptureProxy(); case Repeater -> isCaptureRepeater(); case Target -> isCaptureTarget(); - case Spider -> isCaptureSpider(); case Scanner -> isCaptureScanner(); case Intruder -> isCaptureIntruder(); case Extender -> isCaptureExtender(); case Session -> true; + case WebSockets -> isCaptureWebSockets(); }; } @@ -58,5 +59,10 @@ public enum ImportMethod { File, Url } + + public enum ExportMethod { + Json, + Yaml + } } diff --git a/src/main/java/synfron/reshaper/burp/core/settings/SettingsManager.java b/src/main/java/synfron/reshaper/burp/core/settings/SettingsManager.java index 95f8a86..382fb10 100644 --- a/src/main/java/synfron/reshaper/burp/core/settings/SettingsManager.java +++ b/src/main/java/synfron/reshaper/burp/core/settings/SettingsManager.java @@ -2,6 +2,7 @@ import burp.BurpExtender; import com.fasterxml.jackson.core.type.TypeReference; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.exceptions.WrappedException; import synfron.reshaper.burp.core.rules.Rule; import synfron.reshaper.burp.core.rules.RulesRegistry; @@ -17,7 +18,7 @@ public class SettingsManager { - public void importSettings(File file, boolean overwriteDuplicates) { + public static void importSettings(File file, boolean overwriteDuplicates) { try { importSettings(Files.readString(file.toPath()), overwriteDuplicates); } catch (IOException e) { @@ -25,48 +26,61 @@ public void importSettings(File file, boolean overwriteDuplicates) { } } - public void importSettings(String settingsJson, boolean overwriteDuplicates) { + public static void importSettings(String settingsJson, boolean overwriteDuplicates) { ExportSettings exportSettings = Serializer.deserialize( settingsJson, new TypeReference<>() {} ); getGlobalVariables().importVariables(exportSettings.getVariables(), overwriteDuplicates); - getRulesRegistry().importRules(exportSettings.getRules(), overwriteDuplicates); + getHttpRulesRegistry().importRules(exportSettings.getRules(), overwriteDuplicates); + getWebSocketRulesRegistry().importRules(exportSettings.getWebSocketRules(), overwriteDuplicates); } - public void exportSettings(File file, List variables, List rules) { + public static void exportSettings(File file, List variables, List httpRules, List webSocketRules) { try { ExportSettings exportSettings = new ExportSettings(); exportSettings.setVariables(variables); - exportSettings.setRules(rules); - Files.writeString(file.toPath(), Serializer.serialize(exportSettings, false)); + exportSettings.setRules(httpRules); + exportSettings.setWebSocketRules(webSocketRules); + String data = switch (BurpExtender.getGeneralSettings().getExportMethod()) { + case Json -> Serializer.serialize(exportSettings, false); + case Yaml -> Serializer.serializeYaml(exportSettings, false); + }; + Files.writeString(file.toPath(), data); } catch (IOException e) { throw new WrappedException(e); } } - public void loadSettings() { + public static void loadSettings() { BurpExtender.getGeneralSettings().importSettings(Storage.get("Reshaper.generalSettings", new TypeReference<>() {})); getGlobalVariables().importVariables(Storage.get("Reshaper.variables", new TypeReference<>() {}), false); - getRulesRegistry().importRules(Storage.get("Reshaper.rules", new TypeReference<>() {}), false); + getHttpRulesRegistry().importRules(Storage.get("Reshaper.rules", new TypeReference<>() {}), false); + getWebSocketRulesRegistry().importRules(Storage.get("Reshaper.webSocketRules", new TypeReference<>() {}), false); } - public void saveSettings() { + public static void saveSettings() { Storage.store("Reshaper.generalSettings", BurpExtender.getGeneralSettings()); Storage.store("Reshaper.variables", getGlobalVariables().exportVariables()); - Storage.store("Reshaper.rules", getRulesRegistry().exportRules()); + Storage.store("Reshaper.rules", getHttpRulesRegistry().exportRules()); + Storage.store("Reshaper.webSocketRules", getWebSocketRulesRegistry().exportRules()); } - private GlobalVariables getGlobalVariables() { + private static GlobalVariables getGlobalVariables() { return GlobalVariables.get(); } - private RulesRegistry getRulesRegistry() { - return BurpExtender.getConnector().getRulesEngine().getRulesRegistry(); + private static RulesRegistry getHttpRulesRegistry() { + return BurpExtender.getRulesRegistry(ProtocolType.Http); } - public void resetData() { - Arrays.stream(getRulesRegistry().getRules()).forEach(rule -> getRulesRegistry().deleteRule(rule)); + private static RulesRegistry getWebSocketRulesRegistry() { + return BurpExtender.getRulesRegistry(ProtocolType.WebSocket); + } + + public static void resetData() { + Arrays.stream(getHttpRulesRegistry().getRules()).forEach(rule -> getHttpRulesRegistry().deleteRule(rule)); + Arrays.stream(getWebSocketRulesRegistry().getRules()).forEach(rule -> getWebSocketRulesRegistry().deleteRule(rule)); GlobalVariables.get().getValues().forEach(variable -> GlobalVariables.get().remove(variable.getName())); } } \ No newline at end of file diff --git a/src/main/java/synfron/reshaper/burp/core/settings/Storage.java b/src/main/java/synfron/reshaper/burp/core/settings/Storage.java index 2d5db15..7e26a28 100644 --- a/src/main/java/synfron/reshaper/burp/core/settings/Storage.java +++ b/src/main/java/synfron/reshaper/burp/core/settings/Storage.java @@ -7,11 +7,11 @@ public class Storage { public static void store(String storageKey, Object value) { - BurpExtender.getCallbacks().saveExtensionSetting(storageKey, Serializer.serialize(value, false)); + BurpExtender.getApi().persistence().preferences().setString(storageKey, Serializer.serialize(value, false)); } public static T get(String storageKey, TypeReference typeReference) { - String json = BurpExtender.getCallbacks().loadExtensionSetting(storageKey); + String json = BurpExtender.getApi().persistence().preferences().getString(storageKey); if (json == null) { return null; } diff --git a/src/main/java/synfron/reshaper/burp/core/utils/Log.java b/src/main/java/synfron/reshaper/burp/core/utils/Log.java index 5610c07..aaf8e77 100644 --- a/src/main/java/synfron/reshaper/burp/core/utils/Log.java +++ b/src/main/java/synfron/reshaper/burp/core/utils/Log.java @@ -1,10 +1,10 @@ package synfron.reshaper.burp.core.utils; import burp.BurpExtender; +import burp.api.montoya.core.ByteArray; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; @SuppressWarnings("FieldCanBeLocal") @@ -65,22 +65,24 @@ public void logErr() { private void printOutput(String text, boolean isError) { if (BurpExtender.getGeneralSettings().isLogInExtenderOutput()) { if (isError) { - BurpExtender.getCallbacks().printError(text); + BurpExtender.getApi().logging().logToError(text); } else { - BurpExtender.getCallbacks().printOutput(text); + BurpExtender.getApi().logging().logToOutput(text); } } printToDisplay(text); } private void printToDisplay(String text) { - BurpExtender.getLogTextEditor().setText( - TextUtils.bufferAppend( - new String(BurpExtender.getLogTextEditor().getText(), StandardCharsets.UTF_8), - text, - "\n", - BurpExtender.getGeneralSettings().getLogTabCharacterLimit() - ).getBytes(StandardCharsets.UTF_8) - ); + if (BurpExtender.getLogTextEditor() != null) { + BurpExtender.getLogTextEditor().setContents(ByteArray.byteArray( + TextUtils.bufferAppend( + new String(BurpExtender.getLogTextEditor().getContents().getBytes(), StandardCharsets.UTF_8), + text, + "\n", + BurpExtender.getGeneralSettings().getLogTabCharacterLimit() + ).getBytes(StandardCharsets.UTF_8) + )); + } } } diff --git a/src/main/java/synfron/reshaper/burp/core/utils/ObjectUtils.java b/src/main/java/synfron/reshaper/burp/core/utils/ObjectUtils.java index 84528b1..598f4d3 100644 --- a/src/main/java/synfron/reshaper/burp/core/utils/ObjectUtils.java +++ b/src/main/java/synfron/reshaper/burp/core/utils/ObjectUtils.java @@ -3,9 +3,6 @@ import synfron.reshaper.burp.core.exceptions.WrappedException; import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Objects; import java.util.stream.Stream; public class ObjectUtils { @@ -18,13 +15,4 @@ public static Object construct(Class clazz, Object... args) { throw new WrappedException(e); } } - - public static URL getUrl(String protocol, String host, int port, String path) throws MalformedURLException { - return new URL( - protocol, - host, - (Objects.equals(protocol, "http") && port == 80) || (Objects.equals(protocol, "https") && port == 443) ? -1 : port, - path - ); - } } diff --git a/src/main/java/synfron/reshaper/burp/core/utils/Protocol.java b/src/main/java/synfron/reshaper/burp/core/utils/Protocol.java new file mode 100644 index 0000000..fb4f243 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/utils/Protocol.java @@ -0,0 +1,42 @@ +package synfron.reshaper.burp.core.utils; + +import lombok.Getter; +import org.apache.commons.lang3.EnumUtils; + +public enum Protocol { + Unknown(false, null, null, false), + Http(false, 80, null, true), + Https(true, 443, null, true), + Ws(false, 80, Http, false), + Wss(true, 443, Https, false); + + @Getter + private final boolean secure; + private final Integer defaultPort; + private final Protocol backupProtocol; + private final boolean javaSupported; + + Protocol(boolean secure, Integer defaultPort, Protocol backupProtocol, boolean javaSupported) { + this.secure = secure; + this.defaultPort = defaultPort; + this.backupProtocol = backupProtocol; + this.javaSupported = javaSupported; + } + + public Integer getDefaultPort() { + return defaultPort; + } + + public int getDefaultPort(int defaultIfNone) { + return defaultPort != null ? defaultPort : defaultIfNone; + } + + public static String getJavaSupportProtocol(String protocolValue) { + Protocol protocol = get(protocolValue); + return protocol.javaSupported || protocol.backupProtocol == null ? protocolValue : protocol.backupProtocol.name().toLowerCase(); + } + + public static Protocol get(String protocol) { + return EnumUtils.getEnumIgnoreCase(Protocol.class, protocol, Protocol.Unknown); + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/utils/Serializer.java b/src/main/java/synfron/reshaper/burp/core/utils/Serializer.java index 1b7f090..e452f57 100644 --- a/src/main/java/synfron/reshaper/burp/core/utils/Serializer.java +++ b/src/main/java/synfron/reshaper/burp/core/utils/Serializer.java @@ -3,20 +3,40 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonTokenId; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; +import lombok.Getter; import synfron.reshaper.burp.core.exceptions.WrappedException; import synfron.reshaper.burp.core.vars.VariableString; import java.io.IOException; +import java.io.StringWriter; import java.util.stream.Stream; public class Serializer { + @Getter private static ObjectMapper objectMapper; + private static JsonFactory jsonFactory = new JsonFactory(); + + static { + VariableStringSerializer variableStringSerializer = new VariableStringSerializer(); + VariableStringDeserializer variableStringDeserializer = new VariableStringDeserializer(); + ObjectMapper objectMapper = configureMapper(new JsonSerializer[]{ variableStringSerializer }, new JsonDeserializer[] { variableStringDeserializer }); + SimpleModule module = new SimpleModule(); + module.addSerializer(VariableString.class, variableStringSerializer); + module.addDeserializer(VariableString.class, variableStringDeserializer); + objectMapper.registerModule(module); + + Serializer.objectMapper = objectMapper; + } private static ObjectMapper configureMapper(JsonDeserializer[] deserializers) { return configureMapper(new JsonSerializer[0], deserializers); @@ -31,7 +51,8 @@ private static ObjectMapper configureMapper() { } private static ObjectMapper configureMapper(JsonSerializer[] serializers, JsonDeserializer[] deserializers) { - JsonMapper.Builder builder = JsonMapper.builder(); + JsonMapper.Builder builder = JsonMapper.builder(YAMLFactory.builder() + .disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER).build()); builder.serializationInclusion(JsonInclude.Include.NON_NULL); builder.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true); builder.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); @@ -57,28 +78,29 @@ private static void addDeserializer(SimpleModule module, Class type, Json module.addDeserializer(type, (JsonDeserializer)deserializer); } - private static ObjectMapper getObjectMapper() { - if (objectMapper == null) { - ObjectMapper objectMapper = configureMapper(new JsonDeserializer[] { new VariableStringDeserializer() }); - SimpleModule module = new SimpleModule(); - module.addDeserializer(VariableString.class, new VariableStringDeserializer()); - objectMapper.registerModule(module); - - Serializer.objectMapper = objectMapper; - } - return objectMapper; - } - @SuppressWarnings("unchecked") public static T copy(T source) { return deserialize(serialize(source, false), (Class)source.getClass()); } public static String serialize(Object value, boolean prettyPrint) { + try { + StringWriter stringWriter = new StringWriter(); + (prettyPrint ? + objectMapper.writer().withDefaultPrettyPrinter() : + objectMapper.writer() + ).writeValue(jsonFactory.createGenerator(stringWriter), value); + return stringWriter.toString(); + } catch (IOException e) { + throw new WrappedException(e); + } + } + + public static String serializeYaml(Object value, boolean prettyPrint) { try { return (prettyPrint ? - getObjectMapper().writer().withDefaultPrettyPrinter() : - getObjectMapper().writer() + objectMapper.writer().withDefaultPrettyPrinter() : + objectMapper.writer() ).writeValueAsString(value); } catch (IOException e) { throw new WrappedException(e); @@ -90,7 +112,7 @@ public static T deserialize(String json, TypeReference typeReference) { return null; } try { - return getObjectMapper().readValue(json, typeReference); + return objectMapper.readValue(json, typeReference); } catch (IOException e) { throw new WrappedException(e); } @@ -101,7 +123,7 @@ public static T deserialize(String json, Class clazz) { return null; } try { - return getObjectMapper().readValue(json, clazz); + return objectMapper.readValue(json, clazz); } catch (IOException e) { throw new WrappedException(e); } @@ -121,4 +143,20 @@ public VariableString deserialize(JsonParser parser, DeserializationContext cont objectMapper.readValue(parser, VariableString.class); } } + + private static class VariableStringSerializer extends JsonSerializer { + @Override + public Class handledType() { + return VariableString.class; + } + + @Override + public void serialize(VariableString value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + if (value == null) { + gen.writeNull(); + } else { + gen.writeString(value.toString()); + } + } + } } diff --git a/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java b/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java index 6799101..1678bbd 100644 --- a/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java +++ b/src/main/java/synfron/reshaper/burp/core/utils/TextUtils.java @@ -1,12 +1,10 @@ package synfron.reshaper.burp.core.utils; -import burp.BurpExtender; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPath; import com.jayway.jsonpath.Option; import com.jayway.jsonpath.ParseContext; import net.minidev.json.JSONValue; -import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.NameValuePair; import org.apache.http.client.utils.URLEncodedUtils; @@ -86,8 +84,10 @@ public static String setParamValue(String text, String name, String value) { return URLEncodedUtils.format(params, StandardCharsets.UTF_8); } - public static boolean isMatch(String text, String regex) { - Pattern pattern = Pattern.compile(regex); + public static boolean isMatch(String text, String regex, boolean ignoreCase) { + Pattern pattern = ignoreCase ? + Pattern.compile(regex, Pattern.CASE_INSENSITIVE) : + Pattern.compile(regex); return pattern.matcher(text).find(); } diff --git a/src/main/java/synfron/reshaper/burp/core/utils/Url.java b/src/main/java/synfron/reshaper/burp/core/utils/Url.java new file mode 100644 index 0000000..1313dd0 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/utils/Url.java @@ -0,0 +1,80 @@ +package synfron.reshaper.burp.core.utils; + +import lombok.Getter; +import org.apache.http.client.utils.URIBuilder; +import synfron.reshaper.burp.core.exceptions.WrappedException; + +import java.io.Serializable; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +public class Url implements Serializable { + + @Getter + private final String protocol; + private final URL url; + + private final String urlValue; + + public Url(String urlValue) { + try { + URIBuilder uriBuilder = new URIBuilder(urlValue); + protocol = uriBuilder.getScheme(); + uriBuilder.setScheme(Protocol.getJavaSupportProtocol(protocol)); + this.url = uriBuilder.build().toURL(); + this.urlValue = urlValue; + } catch (URISyntaxException | MalformedURLException e) { + throw new WrappedException(e); + } + } + + public Url(String protocol, String host, int port, String file) + { + try { + this.protocol = protocol; + this.url = new URL(Protocol.getJavaSupportProtocol(protocol), host, port, file); + urlValue = new URIBuilder(url.toString()).setScheme(this.protocol).setPort(getOptionalPort()).build().toString(); + } catch (MalformedURLException | URISyntaxException e) { + throw new WrappedException(e); + } + } + + public URI toURI() { + try { + return new URI(urlValue); + } catch (URISyntaxException e) { + throw new WrappedException(e); + } + } + + public String getHost() { + return url.getHost(); + } + + public int getPort() { + return url.getPort(); + } + + public String getFile() { + return url.getFile(); + } + + public String getAuthority() { + return url.getAuthority(); + } + + public int getOptionalPort() { + return Protocol.get(protocol).getDefaultPort() == url.getPort() ? -1 : url.getPort(); + } + + public Integer getDefaultPort() { + return Protocol.get(protocol).getDefaultPort(); + } + + @Override + public String toString() { + return urlValue; + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/utils/UrlUtils.java b/src/main/java/synfron/reshaper/burp/core/utils/UrlUtils.java new file mode 100644 index 0000000..e173dfb --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/core/utils/UrlUtils.java @@ -0,0 +1,13 @@ +package synfron.reshaper.burp.core.utils; + +public class UrlUtils { + + public static Url getUrl(String protocol, String host, Integer port, String path) { + return new Url( + protocol, + host, + port == null ? Protocol.get(protocol).getDefaultPort(-1) : port, + path + ); + } +} diff --git a/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java b/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java index 4bd32a6..f743451 100644 --- a/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java +++ b/src/main/java/synfron/reshaper/burp/core/vars/VariableSource.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.core.vars; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; import java.util.Arrays; import java.util.List; @@ -9,27 +10,32 @@ @Getter public enum VariableSource { - Event("e", false), - Global("g", false), - Message("m", true), - File("f", true), - Special("s", true), - CookieJar("Cookie Jar", "cj", true); + Event("e", false, ProtocolType.Any), + Global("g", false, ProtocolType.Any), + Session("sn", false, ProtocolType.WebSocket), + Message("m", true, ProtocolType.Any), + Annotation("a", true, ProtocolType.Http), + File("f", true, ProtocolType.Any), + Special("s", true, ProtocolType.Any), + CookieJar("Cookie Jar", "cj", true, ProtocolType.Any); private final String displayName; private final String shortName; private final boolean accessor; + private final ProtocolType protocolType; - VariableSource(String displayName, String shortName, boolean accessor) { + VariableSource(String displayName, String shortName, boolean accessor, ProtocolType protocolType) { this.displayName = displayName; this.shortName = shortName; this.accessor = accessor; + this.protocolType = protocolType; } - VariableSource(String shortName, boolean accessor) { + VariableSource(String shortName, boolean accessor, ProtocolType protocolType) { this.displayName = this.name(); this.shortName = shortName; this.accessor = accessor; + this.protocolType = protocolType; } public static List getSupportedNames() { @@ -39,6 +45,14 @@ public static List getSupportedNames() { ).collect(Collectors.toList()); } + public static VariableSource[] getAllSettables(ProtocolType protocolType) { + return Arrays.stream(values()).filter(value -> value.protocolType.accepts(protocolType) && !value.accessor).toArray(VariableSource[]::new); + } + + public static VariableSource[] getAll(ProtocolType protocolType) { + return Arrays.stream(values()).filter(value -> value.protocolType.accepts(protocolType)).toArray(VariableSource[]::new); + } + public static VariableSource get(String name) { return Arrays.stream(VariableSource.values()) .filter(source -> source.name().equalsIgnoreCase(name) || source.shortName.equalsIgnoreCase(name)) diff --git a/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java b/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java index 21142bc..34e3c2e 100644 --- a/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java +++ b/src/main/java/synfron/reshaper/burp/core/vars/VariableString.java @@ -1,7 +1,7 @@ package synfron.reshaper.burp.core.vars; import burp.BurpExtender; -import burp.ICookie; +import burp.api.montoya.http.message.cookies.Cookie; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; @@ -9,10 +9,7 @@ import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -import synfron.reshaper.burp.core.messages.Encoder; -import synfron.reshaper.burp.core.messages.IEventInfo; -import synfron.reshaper.burp.core.messages.MessageValue; -import synfron.reshaper.burp.core.messages.MessageValueHandler; +import synfron.reshaper.burp.core.messages.*; import synfron.reshaper.burp.core.utils.CollectionUtils; import synfron.reshaper.burp.core.utils.GetItemPlacement; import synfron.reshaper.burp.core.utils.Log; @@ -42,9 +39,10 @@ public VariableString(String text, List variables) { } public static CSVFormat getParamFormat() { - return CSVFormat.DEFAULT.withDelimiter(':') - .withAllowMissingColumnNames(true) - .withEscape('\\'); + return CSVFormat.DEFAULT.builder().setDelimiter(':') + .setAllowMissingColumnNames(true) + .setEscape('\\') + .build(); } public static boolean isValidVariableName(String name) { @@ -107,17 +105,17 @@ public static VariableString getAsVariableString(String str, boolean requiresPar } } - public Integer getInt(IEventInfo eventInfo) + public Integer getInt(EventInfo eventInfo) { return TextUtils.asInt(getText(eventInfo)); } - public Double getDouble(IEventInfo eventInfo) + public Double getDouble(EventInfo eventInfo) { return TextUtils.asDouble(getText(eventInfo)); } - public String getText(IEventInfo eventInfo) + public String getText(EventInfo eventInfo) { List variableVals = new ArrayList<>(); for (VariableSourceEntry variable : variables) @@ -130,6 +128,7 @@ public String getText(IEventInfo eventInfo) case File -> getFileText(eventInfo, variable.getName()); case Special -> variable.getName(); case CookieJar -> getCookie(variable.getName()); + case Annotation -> getAnnotation(eventInfo, variable.getName()); default -> null; }; variableVals.add(value); @@ -137,6 +136,7 @@ public String getText(IEventInfo eventInfo) Variable value = switch (variable.getVariableSource()) { case Global -> GlobalVariables.get().getOrDefault(variable.getName()); case Event -> eventInfo.getVariables().getOrDefault(variable.getName()); + case Session -> eventInfo instanceof WebSocketEventInfo ? ((WebSocketEventInfo)eventInfo).getSessionVariables().getOrDefault(variable.getName()) : null; default -> null; }; variableVals.add(value != null ? TextUtils.toString(value.getValue()) : null); @@ -146,6 +146,18 @@ public String getText(IEventInfo eventInfo) return String.format(text, variableVals.toArray()); } + private String getAnnotation(EventInfo eventInfo, String name) { + MessageAnnotation annotation = EnumUtils.getEnumIgnoreCase(MessageAnnotation.class, name); + if (annotation != null && eventInfo instanceof HttpEventInfo) { + HttpEventInfo httpEventInfo = (HttpEventInfo) eventInfo; + return switch (annotation) { + case Comment -> httpEventInfo.getAnnotations().comment(); + case HighlightColor -> StringUtils.capitalize(httpEventInfo.getAnnotations().highlightColor().name().toLowerCase()); + }; + } + return null; + } + private String getCookie(String locator) { try { String[] parts = locator.split(":", 3); @@ -153,23 +165,24 @@ private String getCookie(String locator) { String name = parts[1]; String path = CollectionUtils.elementAtOrDefault(parts, 2); if (Arrays.stream(parts).anyMatch(part -> part.startsWith("\""))) { - CSVParser csvParser = CSVParser.parse(locator, getParamFormat()); - CSVRecord record = csvParser.getRecords().get(0); - if (record.size() == 2) { - domain = record.get(0); - name = record.get(1); - path = null; - } else if (record.size() == 3) { - domain = record.get(0); - name = record.get(1); - path = record.get(2); + try (CSVParser csvParser = CSVParser.parse(locator, getParamFormat())) { + CSVRecord record = csvParser.getRecords().get(0); + if (record.size() == 2) { + domain = record.get(0); + name = record.get(1); + path = null; + } else if (record.size() == 3) { + domain = record.get(0); + name = record.get(1); + path = record.get(2); + } } } - for (ICookie cookie : BurpExtender.getCallbacks().getCookieJarContents()) { - if (cookie.getDomain().equals(domain) - && cookie.getName().equals(name) - && (path == null || StringUtils.defaultString(cookie.getPath()).equals(path))) { - return cookie.getValue(); + for (Cookie cookie : BurpExtender.getApi().http().cookieJar().cookies()) { + if (cookie.domain().equals(domain) + && cookie.name().equals(name) + && (path == null || StringUtils.defaultString(cookie.path()).equals(path))) { + return cookie.value(); } } } catch (Exception e) { @@ -180,7 +193,7 @@ private String getCookie(String locator) { return ""; } - private String getFileText(IEventInfo eventInfo, String locator) { + private String getFileText(EventInfo eventInfo, String locator) { try { String[] variableNameParts = locator.split(":", 2); File file = new File(variableNameParts[1]); @@ -210,7 +223,7 @@ private static String getSpecialChar(String sequences) { return null; } - private String getMessageVariable(IEventInfo eventInfo, String locator) { + private String getMessageVariable(EventInfo eventInfo, String locator) { String[] variableNameParts = locator.split(":", 2); MessageValue messageValue = EnumUtils.getEnumIgnoreCase(MessageValue.class, CollectionUtils.elementAtOrDefault(variableNameParts, 0, "")); String identifier = CollectionUtils.elementAtOrDefault(variableNameParts, 1, ""); @@ -223,23 +236,23 @@ private String getMessageVariable(IEventInfo eventInfo, String locator) { return null; } - public static String getTextOrDefault(IEventInfo eventInfo, VariableString variableString, String defaultValue) { + public static String getTextOrDefault(EventInfo eventInfo, VariableString variableString, String defaultValue) { return variableString != null && !variableString.isEmpty() ? StringUtils.defaultIfEmpty(variableString.getText(eventInfo), defaultValue) : defaultValue; } - public static String getText(IEventInfo eventInfo, VariableString variableString) { + public static String getText(EventInfo eventInfo, VariableString variableString) { return variableString != null ? variableString.getText(eventInfo) : null; } - public static Integer getIntOrDefault(IEventInfo eventInfo, VariableString variableString, Integer defaultValue) { + public static Integer getIntOrDefault(EventInfo eventInfo, VariableString variableString, Integer defaultValue) { return variableString != null && !variableString.isEmpty() ? variableString.getInt(eventInfo) : defaultValue; } - public static Double getDoubleOrDefault(IEventInfo eventInfo, VariableString variableString, Double defaultValue) { + public static Double getDoubleOrDefault(EventInfo eventInfo, VariableString variableString, Double defaultValue) { return variableString != null && !variableString.isEmpty() ? variableString.getDouble(eventInfo) : defaultValue; diff --git a/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java index 461ea4f..406e0fb 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/IFormComponent.java @@ -2,7 +2,9 @@ import net.miginfocom.swing.MigLayout; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.ui.components.rules.RuleOperationComponent; import synfron.reshaper.burp.ui.components.rules.wizard.vars.VariableTagWizardOptionPane; import synfron.reshaper.burp.ui.models.rules.wizard.vars.VariableTagWizardModel; import synfron.reshaper.burp.ui.utils.ActionPerformedListener; @@ -48,12 +50,16 @@ default JComboBox createComboBox(T[] array, boolean isEditable) { return comboBox; } + private ProtocolType getProtocolType() { + return this instanceof RuleOperationComponent ? ((RuleOperationComponent)this).getProtocolType() : ProtocolType.Any; + } + default JTextField createTextField(boolean supportsVariableTags) { JTextField textField = new JTextField(); textField.setColumns(20); textField.setMaximumSize(new Dimension(textField.getPreferredSize().width, textField.getPreferredSize().height)); textField.setAlignmentX(LEFT_ALIGNMENT); - return addContextMenu(addUndo(textField), supportsVariableTags); + return addContextMenu(addUndo(textField), supportsVariableTags, getProtocolType()); } default Component getPaddedButton(JButton button) { @@ -65,10 +71,10 @@ default Component getPaddedButton(JButton button) { } default JTextPane createTextPane() { - return addContextMenu(addUndo(new JTextPane()), false); + return addContextMenu(addUndo(new JTextPane()), false, getProtocolType()); } - private static T addContextMenu(T textComponent, boolean supportsVariableTags) { + private static T addContextMenu(T textComponent, boolean supportsVariableTags, ProtocolType protocolType) { JPopupMenu popupMenu = new JPopupMenu(); Action cut = new DefaultEditorKit.CutAction(); @@ -87,7 +93,7 @@ private static T addContextMenu(T textComponent, bool popupMenu.add(selectAll); if (supportsVariableTags) { - Action addVariableTag = new ActionPerformedListener(event -> insertVariableTag(textComponent)); + Action addVariableTag = new ActionPerformedListener(event -> insertVariableTag(textComponent, protocolType)); addVariableTag.putValue(Action.NAME, "Insert Variable Tag"); popupMenu.addSeparator(); popupMenu.add(addVariableTag); @@ -98,10 +104,10 @@ private static T addContextMenu(T textComponent, bool return textComponent; } - private static void insertVariableTag(T textComponent) { + private static void insertVariableTag(T textComponent, ProtocolType protocolType) { VariableTagWizardModel model = new VariableTagWizardModel(); do { - ModalPrompter.open(model, ignored -> VariableTagWizardOptionPane.showDialog(model), false); + ModalPrompter.open(model, ignored -> VariableTagWizardOptionPane.showDialog(model, protocolType), false); } while (model.isInvalidated() && !model.isDismissed()); if (!model.isDismissed()) { String tag = model.getTag(); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/LogsComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/LogsComponent.java index 42ba64b..8f60774 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/LogsComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/LogsComponent.java @@ -1,7 +1,8 @@ package synfron.reshaper.burp.ui.components; import burp.BurpExtender; -import burp.ITextEditor; +import burp.api.montoya.core.ByteArray; +import burp.api.montoya.ui.editor.RawEditor; import javax.swing.*; import java.awt.*; @@ -9,7 +10,7 @@ public class LogsComponent extends JPanel { - private final ITextEditor textEditor = BurpExtender.getLogTextEditor(); + private final RawEditor textEditor = BurpExtender.getLogTextEditor(); public LogsComponent() { initComponents(); @@ -18,7 +19,7 @@ public LogsComponent() { private void initComponents() { setLayout(new BorderLayout()); if (textEditor != null) { - add(textEditor.getComponent(), BorderLayout.CENTER); + add(textEditor.uiComponent(), BorderLayout.CENTER); add(getActionBar(), BorderLayout.PAGE_END); } } @@ -35,6 +36,6 @@ private Component getActionBar() { } private void onClear(ActionEvent actionEvent) { - textEditor.setText(new byte[0]); + textEditor.setContents(ByteArray.byteArray(new byte[0])); } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java index 1dc24d1..d72a9e2 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/ReshaperComponent.java @@ -5,7 +5,7 @@ */ package synfron.reshaper.burp.ui.components; -import burp.ITab; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.ui.components.rules.RulesTabComponent; import synfron.reshaper.burp.ui.components.settings.SettingsTabComponent; import synfron.reshaper.burp.ui.components.vars.VariablesTabComponent; @@ -13,7 +13,7 @@ import javax.swing.*; import java.awt.*; -public class ReshaperComponent extends JPanel implements ITab { +public class ReshaperComponent extends JPanel { public ReshaperComponent() { initComponents(); @@ -27,20 +27,11 @@ private void initComponents() { private JTabbedPane getTabs() { JTabbedPane tabs = new JTabbedPane(); - tabs.addTab("Rules", new RulesTabComponent()); + tabs.addTab("HTTP Rules", new RulesTabComponent(ProtocolType.Http)); + tabs.addTab("WebSocket Rules", new RulesTabComponent(ProtocolType.WebSocket)); tabs.addTab("Global Variables", new VariablesTabComponent()); tabs.addTab("Logs", new LogsComponent()); tabs.addTab("Settings", new SettingsTabComponent()); return tabs; } - - @Override - public String getTabCaption() { - return "Reshaper"; - } - - @Override - public Component getUiComponent() { - return this; - } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java index 6d5a7cd..92eee82 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules; import lombok.SneakyThrows; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.ui.components.IFormComponent; @@ -17,6 +18,7 @@ import java.util.Map; public class RuleComponent extends JPanel implements IFormComponent { + private final ProtocolType protocolType; private final RuleModel model; private JCheckBox isEnabled; private JCheckBox autoRun; @@ -24,7 +26,8 @@ public class RuleComponent extends JPanel implements IFormComponent { private JButton save; private final IEventListener modelPropertyChangedListener = this::onModelPropertyChanged; - public RuleComponent(RuleModel model) { + public RuleComponent(ProtocolType protocolType, RuleModel model) { + this.protocolType = protocolType; this.model = model; model.getPropertyChangedEvent().add(modelPropertyChangedListener); @@ -41,7 +44,7 @@ private void initComponent() { } private Component getRuleOperations() { - return new RuleOperationsContainerComponent(model); + return new RuleOperationsContainerComponent(protocolType, model); } private void setSaveButtonState() { @@ -75,7 +78,7 @@ private Component getRuleNameBox() { } private Component getGitHubLink() { - JLabel githubLink = new JLabel("Help"); + JLabel githubLink = new JLabel("Help | View on GitHub"); githubLink.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); Font font = githubLink.getFont(); Map attributes = font.getAttributes(); @@ -84,6 +87,18 @@ private Component getGitHubLink() { githubLink.addMouseListener(new MouseListener() { private final Color originalColor = githubLink.getForeground(); + private Color hoverColor; + + private Color getHoverColor() { + if (hoverColor == null) { + int halfByte = 128; + int newRed = (halfByte + originalColor.getRed()) / 2; + int newGreen = (halfByte + originalColor.getGreen()) / 2; + int newBlue = (halfByte + originalColor.getBlue()) / 2; + hoverColor = new Color(newRed, newGreen, newBlue); + } + return hoverColor; + } @SneakyThrows @Override @@ -99,7 +114,7 @@ public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) { - githubLink.setForeground(new Color(0, 0, 0xC0)); + githubLink.setForeground(getHoverColor()); } @Override diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleContainerComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleContainerComponent.java index 62a4a56..64ad103 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleContainerComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleContainerComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.ui.models.rules.RuleModel; import javax.swing.*; @@ -7,7 +8,10 @@ public class RuleContainerComponent extends JPanel { - public RuleContainerComponent() { + private final ProtocolType protocolType; + + public RuleContainerComponent(ProtocolType protocolType) { + this.protocolType = protocolType; initComponent(); } @@ -18,7 +22,7 @@ private void initComponent() { public void setModel(RuleModel model) { removeAll(); if (model != null) { - add(new RuleComponent(model)); + add(new RuleComponent(protocolType, model)); } revalidate(); repaint(); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java index c76349f..9f36af2 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleListComponent.java @@ -1,13 +1,17 @@ package synfron.reshaper.burp.ui.components.rules; import burp.BurpExtender; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.CollectionChangedArgs; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.rules.Rule; +import synfron.reshaper.burp.core.rules.RulesRegistry; import synfron.reshaper.burp.core.rules.whens.When; import synfron.reshaper.burp.core.rules.whens.WhenEventDirection; +import synfron.reshaper.burp.core.rules.whens.WhenWebSocketEventDirection; import synfron.reshaper.burp.ui.models.rules.RuleModel; +import synfron.reshaper.burp.ui.utils.ActionPerformedListener; import synfron.reshaper.burp.ui.utils.ForegroundColorListCellRenderer; import synfron.reshaper.burp.ui.utils.WrapLayout; @@ -15,7 +19,7 @@ import javax.swing.event.ListSelectionEvent; import java.awt.*; import java.awt.event.ActionEvent; -import java.util.Arrays; +import java.awt.event.MouseEvent; import java.util.Collections; import java.util.Map; import java.util.function.Function; @@ -23,13 +27,17 @@ import java.util.stream.Stream; public class RuleListComponent extends JPanel { + private final ProtocolType protocolType; + private final RulesRegistry rulesRegistry; private JList rulesList; private DefaultListModel ruleListModel; private RuleContainerComponent ruleContainer; private final IEventListener ruleModelChangeListener = this::onRuleModelChange; private final IEventListener rulesCollectionChangedListener = this::onRulesCollectionChanged; - public RuleListComponent() { + public RuleListComponent(ProtocolType protocolType) { + this.protocolType = protocolType; + this.rulesRegistry = BurpExtender.getRulesRegistry(protocolType); initComponent(); } @@ -37,28 +45,64 @@ private void initComponent() { setLayout(new BorderLayout()); ruleListModel = new DefaultListModel<>(); - ruleListModel.addAll(Stream.of(BurpExtender.getConnector().getRulesEngine().getRulesRegistry().getRules()) - .map(rule -> new RuleModel(rule).withListener(ruleModelChangeListener)) + ruleListModel.addAll(Stream.of(rulesRegistry.getRules()) + .map(rule -> new RuleModel(protocolType, rule).withListener(ruleModelChangeListener)) .collect(Collectors.toList())); - rulesList = new JList<>(ruleListModel); + rulesList = getRulesList(); rulesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); rulesList.setCellRenderer(new ForegroundColorListCellRenderer(this::ruleListItemColorProvider)); JScrollPane scrollPane = new JScrollPane(); scrollPane.setViewportView(rulesList); - BurpExtender.getConnector().getRulesEngine().getRulesRegistry().getCollectionChangedEvent().add(rulesCollectionChangedListener); + rulesRegistry.getCollectionChangedEvent().add(rulesCollectionChangedListener); rulesList.addListSelectionListener(this::onSelectionChanged); add(scrollPane, BorderLayout.CENTER); add(getActionBar(), BorderLayout.PAGE_END); } + private JList getRulesList() { + return new JList<>(ruleListModel) { + + private RuleModel mouseActionItem; + + @Override + public JPopupMenu getComponentPopupMenu() { + if (mouseActionItem != null && !mouseActionItem.isNew()) { + JPopupMenu popupMenu = new JPopupMenu(); + Action toggleDiagnostics = new ActionPerformedListener(event -> mouseActionItem.getRule().setDiagnosticsEnabled(!mouseActionItem.isDiagnosticsEnabled())); + + toggleDiagnostics.putValue(Action.NAME, "Toggle Debug Logging"); + + popupMenu.add(toggleDiagnostics); + + return popupMenu; + } + return super.getComponentPopupMenu(); + } + + @Override + protected void processMouseEvent(MouseEvent e) { + if (e.getID() == MouseEvent.MOUSE_PRESSED) { + JList jList = (JList) e.getSource(); + int itemIndex = jList.locationToIndex(e.getPoint()); + if (itemIndex >= 0) { + mouseActionItem = (RuleModel) jList.getModel().getElementAt(itemIndex); + } else { + mouseActionItem = null; + } + } + super.processMouseEvent(e); + } + }; + } + private Color ruleListItemColorProvider(Object item, Color defaultColor) { Color newColor = null; if (item instanceof RuleModel) { - RuleModel model = (RuleModel)item; + RuleModel model = (RuleModel) item; if (!model.isEnabled()) { newColor = new Color( rgbScaler(defaultColor.getRed(), 2.6), @@ -71,15 +115,14 @@ private Color ruleListItemColorProvider(Object item, Color defaultColor) { } private int rgbScaler(int value, double divisor) { - return (int)(value-((value-(0xFF^value))/divisor)); + return (int) (value - ((value - (0xFF ^ value)) / divisor)); } private void onSelectionChanged(ListSelectionEvent listSelectionEvent) { RuleModel rule = rulesList.getSelectedValue(); if (rule != null) { ruleContainer.setModel(rule); - } - else if (!defaultSelect()) { + } else if (!defaultSelect()) { ruleContainer.setModel(null); } } @@ -96,7 +139,7 @@ private void onRulesCollectionChanged(CollectionChangedArgs collectionChangedArg switch (collectionChangedArgs.getAction()) { case Add -> { Rule item = (Rule) collectionChangedArgs.getItem(); - RuleModel model = new RuleModel(item, true).withListener(ruleModelChangeListener); + RuleModel model = new RuleModel(protocolType, item, true).withListener(ruleModelChangeListener); ruleListModel.addElement(model); rulesList.setSelectedValue(model, true); } @@ -122,10 +165,10 @@ private void onRulesCollectionChanged(CollectionChangedArgs collectionChangedArg ruleListModel.elements()).stream().collect(Collectors.toMap(RuleModel::getRule, Function.identity()) ); ruleListModel.clear(); - ruleListModel.addAll(Stream.of(BurpExtender.getConnector().getRulesEngine().getRulesRegistry().getRules()) + ruleListModel.addAll(Stream.of(rulesRegistry.getRules()) .map(rule -> ruleModelMap.containsKey(rule) ? ruleModelMap.get(rule) : - new RuleModel(rule).withListener(ruleModelChangeListener) + new RuleModel(protocolType, rule).withListener(ruleModelChangeListener) ).collect(Collectors.toList())); defaultSelect(); } @@ -157,7 +200,7 @@ private Component getActionBar() { } private void onRuleModelChange(PropertyChangedArgs propertyChangedArgs) { - RuleModel model = (RuleModel)propertyChangedArgs.getSource(); + RuleModel model = (RuleModel) propertyChangedArgs.getSource(); int index = ruleListModel.indexOf(model); ruleListModel.set(index, model); } @@ -165,7 +208,7 @@ private void onRuleModelChange(PropertyChangedArgs propertyChangedArgs) { private void onDelete(ActionEvent actionEvent) { RuleModel rule = rulesList.getSelectedValue(); if (rule != null) { - BurpExtender.getConnector().getRulesEngine().getRulesRegistry().deleteRule(rule.getRule()); + rulesRegistry.deleteRule(rule.getRule()); } } @@ -173,7 +216,7 @@ private void onMoveDown(ActionEvent actionEvent) { RuleModel rule = rulesList.getSelectedValue(); int index = rulesList.getSelectedIndex(); if (rule != null && index < ruleListModel.size() - 1) { - BurpExtender.getConnector().getRulesEngine().getRulesRegistry().moveNext(rule.getRule()); + rulesRegistry.moveNext(rule.getRule()); } } @@ -181,18 +224,18 @@ private void onMoveUp(ActionEvent actionEvent) { RuleModel rule = rulesList.getSelectedValue(); int index = rulesList.getSelectedIndex(); if (rule != null && index > 0) { - BurpExtender.getConnector().getRulesEngine().getRulesRegistry().movePrevious(rule.getRule()); + rulesRegistry.movePrevious(rule.getRule()); } } private void onAdd(ActionEvent actionEvent) { - BurpExtender.getConnector().getRulesEngine().getRulesRegistry().addRule(createNewRule()); + rulesRegistry.addRule(createNewRule()); } private void onDuplicate(ActionEvent actionEvent) { RuleModel rule = rulesList.getSelectedValue(); if (rule != null) { - BurpExtender.getConnector().getRulesEngine().getRulesRegistry().addRule(rule.getRule().copy()); + rulesRegistry.addRule(rule.getRule().copy()); } } @@ -200,7 +243,7 @@ public void setSelectionContainer(RuleContainerComponent ruleContainer) { this.ruleContainer = ruleContainer; if (ruleListModel.size() == 0) { - BurpExtender.getConnector().getRulesEngine().getRulesRegistry().addRule(createNewRule()); + rulesRegistry.addRule(createNewRule()); } defaultSelect(); } @@ -208,7 +251,7 @@ public void setSelectionContainer(RuleContainerComponent ruleContainer) { private Rule createNewRule() { Rule rule = new Rule(); rule.setEnabled(false); - rule.setWhens(new When[]{ new WhenEventDirection() }); + rule.setWhens(new When[]{protocolType == ProtocolType.Http ? new WhenEventDirection() : new WhenWebSocketEventDirection()}); return rule; } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java index b780745..6dadc69 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationComponent.java @@ -2,6 +2,7 @@ import lombok.Getter; import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.rules.IRuleOperation; @@ -13,13 +14,16 @@ public abstract class RuleOperationComponent

, T extends IRuleOperation> extends JScrollPane implements IFormComponent { + @Getter + protected final ProtocolType protocolType; @Getter protected final P model; protected final JPanel mainContainer; protected final JButton validate; private final IEventListener modelPropertyChangedListener = this::onModelPropertyChanged; - protected RuleOperationComponent(P model) { + protected RuleOperationComponent(ProtocolType protocolType, P model) { + this.protocolType = protocolType; this.model = model; mainContainer = new JPanel(new MigLayout()); setViewportView(mainContainer); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationContainerComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationContainerComponent.java index 549d587..081556e 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationContainerComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationContainerComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.utils.ObjectUtils; import synfron.reshaper.burp.ui.models.rules.RuleOperationModel; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -10,7 +11,10 @@ public abstract class RuleOperationContainerComponent extends JPanel { - public RuleOperationContainerComponent() { + private final ProtocolType protocolType; + + public RuleOperationContainerComponent(ProtocolType protocolType) { + this.protocolType = protocolType; initComponent(); } @@ -29,7 +33,7 @@ public void setModel(RuleOperationModel model) { private Component getComponent(RuleOperationModel model) { Class componentClass = getComponentMap().get(model.getType()); - return (Component)ObjectUtils.construct(componentClass, model); + return (Component)ObjectUtils.construct(componentClass, protocolType, model); } protected abstract Map, Class> getComponentMap(); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java index ac69b56..08a60e5 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationListComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.rules.IRuleOperation; @@ -14,9 +15,11 @@ import javax.swing.event.ListSelectionEvent; import java.awt.*; import java.awt.event.ActionEvent; +import java.util.Comparator; import java.util.List; public abstract class RuleOperationListComponent> extends JPanel implements IFormComponent { + protected final ProtocolType protocolType; protected final RuleModel model; protected JList operationsList; protected DefaultListModel operationsListModel; @@ -25,7 +28,8 @@ public abstract class RuleOperationListComponent ruleOperationChangedListener = this::onRuleOperationChanged; - public RuleOperationListComponent(RuleModel model) { + public RuleOperationListComponent(ProtocolType protocolType, RuleModel model) { + this.protocolType = protocolType; this.model = model; setModelChangedListeners(); initComponent(); @@ -118,7 +122,9 @@ private Component getActionBar() { private Component getAddOperation() { JPanel container = new JPanel(); - operationSelector = createComboBox(getRuleOperationModelTypes().toArray(new RuleOperationModelType[0])); + operationSelector = createComboBox(getRuleOperationModelTypes().stream() + .sorted(Comparator.comparing(RuleOperationModelType::getName)) + .toArray(RuleOperationModelType[]::new)); JButton add = new JButton("Add"); add.addActionListener(this::onAdd); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationsComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationsComponent.java index bc78e83..55b66f4 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationsComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationsComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules; import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.ui.models.rules.RuleOperationModel; import synfron.reshaper.burp.ui.models.rules.RuleModel; @@ -9,10 +10,13 @@ public abstract class RuleOperationsComponent> extends JPanel { + protected final ProtocolType protocolType; + protected final RuleModel model; protected JPanel ruleOperationContainer; - public RuleOperationsComponent(RuleModel model) { + public RuleOperationsComponent(ProtocolType protocolType, RuleModel model) { + this.protocolType = protocolType; this.model = model; initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationsContainerComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationsContainerComponent.java index 98f63c2..befa9bb 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationsContainerComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RuleOperationsContainerComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.ui.components.rules.thens.ThensComponent; import synfron.reshaper.burp.ui.components.rules.whens.WhensComponent; import synfron.reshaper.burp.ui.models.rules.RuleModel; @@ -8,9 +9,11 @@ import java.awt.*; public class RuleOperationsContainerComponent extends JPanel { + private final ProtocolType protocolType; private final RuleModel model; - public RuleOperationsContainerComponent(RuleModel model) { + public RuleOperationsContainerComponent(ProtocolType protocolType, RuleModel model) { + this.protocolType = protocolType; this.model = model; initComponent(); } @@ -26,7 +29,7 @@ private Component getWhens() { JPanel container = new JPanel(new BorderLayout()); container.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); - WhensComponent whens = new WhensComponent(model); + WhensComponent whens = new WhensComponent(protocolType, model); container.add(whens); return container; @@ -36,7 +39,7 @@ private Component getThens() { JPanel container = new JPanel(new BorderLayout()); container.setBorder(BorderFactory.createEmptyBorder(0, 2, 0, 2)); - ThensComponent thens = new ThensComponent(model); + ThensComponent thens = new ThensComponent(protocolType, model); container.add(thens); return container; diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/RulesTabComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/RulesTabComponent.java index 3b311ad..748f139 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/RulesTabComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/RulesTabComponent.java @@ -1,19 +1,24 @@ package synfron.reshaper.burp.ui.components.rules; +import synfron.reshaper.burp.core.ProtocolType; + import javax.swing.*; import java.awt.*; public class RulesTabComponent extends JPanel { - public RulesTabComponent() { + private final ProtocolType protocolType; + + public RulesTabComponent(ProtocolType protocolType) { + this.protocolType = protocolType; initComponent(); } private void initComponent() { setLayout(new BorderLayout()); - RuleListComponent ruleList = new RuleListComponent(); - RuleContainerComponent ruleContainer = new RuleContainerComponent(); + RuleListComponent ruleList = new RuleListComponent(protocolType); + RuleContainerComponent ruleContainer = new RuleContainerComponent(protocolType); ruleList.setSelectionContainer(ruleContainer); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, ruleList, ruleContainer); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBreakComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBreakComponent.java index 7a2afb5..e2e58fb 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBreakComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBreakComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.thens.ThenBreak; import synfron.reshaper.burp.ui.models.rules.thens.ThenBreakModel; @@ -10,8 +11,8 @@ public class ThenBreakComponent extends ThenComponent { private JComboBox breakType; - public ThenBreakComponent(ThenBreakModel then) { - super(then); + public ThenBreakComponent(ProtocolType protocolType, ThenBreakModel then) { + super(protocolType, then); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBuildHttpMessageComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBuildHttpMessageComponent.java index ee7b427..de55568 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBuildHttpMessageComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenBuildHttpMessageComponent.java @@ -1,9 +1,10 @@ package synfron.reshaper.burp.ui.components.rules.thens; import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.rules.thens.ThenBuildHttpMessage; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.ui.components.rules.thens.buildhttpmessage.MessageValueSetterComponent; @@ -16,22 +17,22 @@ import java.util.ArrayList; public class ThenBuildHttpMessageComponent extends ThenComponent { - private JComboBox dataDirection; + private JComboBox dataDirection; private JTextField starterHttpMessage; private JComboBox destinationVariableSource; private JTextField destinationVariableName; private JPanel messageValueSettersComponent; private final IEventListener messageValueSetterChangedListener = this::onMessageValueSetterChanged; - public ThenBuildHttpMessageComponent(ThenBuildHttpMessageModel then) { - super(then); + public ThenBuildHttpMessageComponent(ProtocolType protocolType, ThenBuildHttpMessageModel then) { + super(protocolType, then); initComponent(); } private void initComponent() { - dataDirection = createComboBox(DataDirection.values()); + dataDirection = createComboBox(HttpDataDirection.values()); starterHttpMessage = createTextField(true); - destinationVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + destinationVariableSource = createComboBox(VariableSource.getAllSettables(protocolType)); destinationVariableName = createTextField(true); JButton addSetter = new JButton("Add Setter"); @@ -76,7 +77,7 @@ private void onSetDataDirectionChanged(ActionEvent actionEvent) { for (MessageValueSetterModel messageValueSetterModel : new ArrayList<>(model.getMessageValueSetters())) { removeMessageValueSetter(messageValueSetterModel); } - model.setDataDirection((DataDirection) dataDirection.getSelectedItem()); + model.setDataDirection((HttpDataDirection) dataDirection.getSelectedItem()); addMessageValueSetter(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenCommentComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenCommentComponent.java index d0b6261..2bcafa3 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenCommentComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenCommentComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenComment; import synfron.reshaper.burp.ui.models.rules.thens.ThenCommentModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -10,8 +11,8 @@ public class ThenCommentComponent extends ThenComponent { private JTextField text; - public ThenCommentComponent(ThenCommentModel then) { - super(then); + public ThenCommentComponent(ProtocolType protocolType, ThenCommentModel then) { + super(protocolType, then); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenComponent.java index 5efb318..41b082a 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.Then; import synfron.reshaper.burp.ui.components.rules.RuleOperationComponent; import synfron.reshaper.burp.ui.models.rules.thens.ThenModel; @@ -9,8 +10,8 @@ public abstract class ThenComponent

, T extends Then> extends RuleOperationComponent { - public ThenComponent(P model) { - super(model); + public ThenComponent(ProtocolType protocolType, P model) { + super(protocolType, model); setBorder(new CompoundBorder( BorderFactory.createTitledBorder(String.format("Then %s", model.getType().getName())), BorderFactory.createEmptyBorder(4,4,4,4)) diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java index 6fd93fc..173b8a2 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenContainerComponent.java @@ -1,6 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; -import synfron.reshaper.burp.core.rules.thens.ThenEvaluate; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.ui.components.rules.RuleOperationContainerComponent; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import synfron.reshaper.burp.ui.models.rules.thens.ThenModelType; @@ -35,7 +35,13 @@ public class ThenContainerComponent extends RuleOperationContainerComponent { componentMap.put(ThenModelType.BuildHttpMessage, ThenBuildHttpMessageComponent.class); componentMap.put(ThenModelType.ParseHttpMessage, ThenParseHttpMessageComponent.class); componentMap.put(ThenModelType.SendRequest, ThenSendRequestComponent.class); + componentMap.put(ThenModelType.SendMessage, ThenSendMessageComponent.class); componentMap.put(ThenModelType.Drop, ThenDropComponent.class); + componentMap.put(ThenModelType.Intercept, ThenInterceptComponent.class); + } + + public ThenContainerComponent(ProtocolType protocolType) { + super(protocolType); } @Override diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDelayComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDelayComponent.java index c204a75..021138b 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDelayComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDelayComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenDelay; import synfron.reshaper.burp.ui.models.rules.thens.ThenDelayModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -10,8 +11,8 @@ public class ThenDelayComponent extends ThenComponent { private JTextField delay; - public ThenDelayComponent(ThenDelayModel then) { - super(then); + public ThenDelayComponent(ProtocolType protocolType, ThenDelayModel then) { + super(protocolType, then); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteValueComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteValueComponent.java index ba2873b..eadde9d 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteValueComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteValueComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.rules.thens.ThenDeleteValue; import synfron.reshaper.burp.core.utils.DeleteItemPlacement; @@ -10,37 +11,20 @@ import javax.swing.*; import java.awt.event.ActionEvent; import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; public class ThenDeleteValueComponent extends ThenComponent { protected JComboBox messageValue; protected JTextField identifier; protected JComboBox identifierPlacement; - private final Set excludedMessageValues = new HashSet<>(List.of( - MessageValue.DestinationAddress, - MessageValue.DestinationPort, - MessageValue.HttpProtocol, - MessageValue.Url, - MessageValue.HttpRequestMessage, - MessageValue.HttpRequestMethod, - MessageValue.HttpResponseMessage, - MessageValue.HttpRequestStatusLine, - MessageValue.HttpResponseStatusLine, - MessageValue.SourceAddress, - MessageValue.HttpRequestUri, - MessageValue.HttpResponseStatusCode - )); - public ThenDeleteValueComponent(ThenDeleteValueModel then) { - super(then); + public ThenDeleteValueComponent(ProtocolType protocolType, ThenDeleteValueModel then) { + super(protocolType, then); initComponent(); } private void initComponent() { messageValue = createComboBox(Arrays.stream(MessageValue.values()) - .filter(value -> !excludedMessageValues.contains(value)) + .filter(value -> value.isDeletable(protocolType)) .toArray(MessageValue[]::new) ); identifier = createTextField(true); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteVariableComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteVariableComponent.java index b3bd760..3a07ba5 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteVariableComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDeleteVariableComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenDeleteVariable; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.ui.models.rules.thens.ThenDeleteVariableModel; @@ -12,13 +13,13 @@ public class ThenDeleteVariableComponent extends ThenComponent targetSource; private JTextField variableName; - public ThenDeleteVariableComponent(ThenDeleteVariableModel then) { - super(then); + public ThenDeleteVariableComponent(ProtocolType protocolType, ThenDeleteVariableModel then) { + super(protocolType, then); initComponent(); } private void initComponent() { - targetSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + targetSource = createComboBox(VariableSource.getAllSettables(protocolType)); variableName = createTextField(true); targetSource.setSelectedItem(model.getTargetSource()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDropComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDropComponent.java index 436bd20..e9b831e 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDropComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenDropComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenDrop; import synfron.reshaper.burp.ui.models.rules.thens.ThenDropModel; @@ -9,8 +10,8 @@ public class ThenDropComponent extends ThenComponent { private JCheckBox dropMessage; - public ThenDropComponent(ThenDropModel then) { - super(then); + public ThenDropComponent(ProtocolType protocolType, ThenDropModel then) { + super(protocolType, then); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenEvaluateComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenEvaluateComponent.java index 972cf62..76d2cdd 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenEvaluateComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenEvaluateComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenEvaluate; import synfron.reshaper.burp.core.rules.thens.entities.evaluate.Operation; import synfron.reshaper.burp.core.vars.VariableSource; @@ -17,8 +18,8 @@ public class ThenEvaluateComponent extends ThenComponent destinationVariableSource; private JTextField destinationVariableName; - public ThenEvaluateComponent(ThenEvaluateModel then) { - super(then); + public ThenEvaluateComponent(ProtocolType protocolType, ThenEvaluateModel then) { + super(protocolType, then); initComponent(); } @@ -26,7 +27,7 @@ private void initComponent() { x = createTextField(true); operation = createComboBox(Operation.values()); y = createTextField(true); - destinationVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + destinationVariableSource = createComboBox(VariableSource.getAllSettables(protocolType)); destinationVariableName = createTextField(true); x.setText(model.getX()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenHighlightComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenHighlightComponent.java index d4c9c27..3b3826d 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenHighlightComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenHighlightComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenHighlight; import synfron.reshaper.burp.ui.models.rules.thens.ThenHighlightModel; @@ -9,8 +10,8 @@ public class ThenHighlightComponent extends ThenComponent { private JComboBox color; - public ThenHighlightComponent(ThenHighlightModel then) { - super(then); + public ThenHighlightComponent(ProtocolType protocolType, ThenHighlightModel then) { + super(protocolType, then); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenInterceptComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenInterceptComponent.java new file mode 100644 index 0000000..25c3435 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenInterceptComponent.java @@ -0,0 +1,33 @@ +package synfron.reshaper.burp.ui.components.rules.thens; + +import synfron.reshaper.burp.core.InterceptResponse; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.rules.thens.ThenIntercept; +import synfron.reshaper.burp.ui.models.rules.thens.ThenInterceptModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class ThenInterceptComponent extends ThenComponent { + private JComboBox interceptResponse; + + public ThenInterceptComponent(ProtocolType protocolType, ThenInterceptModel then) { + super(protocolType, then); + initComponent(); + } + + private void initComponent() { + interceptResponse = createComboBox(ThenIntercept.getSupportedResponses()); + + interceptResponse.setSelectedItem(model.getInterceptResponse()); + + interceptResponse.addActionListener(this::onInterceptResponseChanged); + + mainContainer.add(getLabeledField("Action", interceptResponse), "wrap"); + mainContainer.add(getPaddedButton(validate)); + } + + private void onInterceptResponseChanged(ActionEvent actionEvent) { + model.setInterceptResponse((InterceptResponse)interceptResponse.getSelectedItem()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenListComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenListComponent.java index 3922759..f21969c 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenListComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenListComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.IRuleOperation; import synfron.reshaper.burp.core.rules.thens.Then; import synfron.reshaper.burp.ui.components.rules.RuleOperationListComponent; @@ -13,8 +14,8 @@ public class ThenListComponent extends RuleOperationListComponent> { - public ThenListComponent(RuleModel model) { - super(model); + public ThenListComponent(ProtocolType protocolType, RuleModel model) { + super(protocolType, model); } @Override @@ -24,16 +25,16 @@ public ThenListComponent(RuleModel model) { @Override protected List> getRuleOperationModelTypes() { - return Collections.unmodifiableList(ThenModelType.getTypes()); + return Collections.unmodifiableList(ThenModelType.getTypes(protocolType)); } @Override protected ThenModel getNewModel(RuleOperationModelType ruleOperationModelType) { - return ThenModel.getNewModel(ruleOperationModelType); + return ThenModel.getNewModel(protocolType, ruleOperationModelType); } @Override protected > ThenModel getModel(R then) { - return ThenModel.getModel((Then)then); + return ThenModel.getModel(protocolType, (Then)then); } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenLogComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenLogComponent.java index 3593ae2..30587f5 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenLogComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenLogComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenLog; import synfron.reshaper.burp.ui.models.rules.thens.ThenLogModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -10,8 +11,8 @@ public class ThenLogComponent extends ThenComponent { private JTextField text; - public ThenLogComponent(ThenLogModel then) { - super(then); + public ThenLogComponent(ProtocolType protocolType, ThenLogModel then) { + super(protocolType, then); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenParseHttpMessageComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenParseHttpMessageComponent.java index 83cb5fb..be13d47 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenParseHttpMessageComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenParseHttpMessageComponent.java @@ -1,9 +1,10 @@ package synfron.reshaper.burp.ui.components.rules.thens; import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.rules.thens.ThenParseHttpMessage; import synfron.reshaper.burp.ui.components.rules.thens.parsehttpmessage.MessageValueGetterComponent; import synfron.reshaper.burp.ui.models.rules.thens.ThenParseHttpMessageModel; @@ -15,18 +16,18 @@ import java.util.ArrayList; public class ThenParseHttpMessageComponent extends ThenComponent { - private JComboBox dataDirection; + private JComboBox dataDirection; private JTextField httpMessage; private JPanel messageValueGettersComponent; private final IEventListener messageValueGetterChangedListener = this::onMessageValueGetterChanged; - public ThenParseHttpMessageComponent(ThenParseHttpMessageModel then) { - super(then); + public ThenParseHttpMessageComponent(ProtocolType protocolType, ThenParseHttpMessageModel then) { + super(protocolType, then); initComponent(); } private void initComponent() { - dataDirection = createComboBox(DataDirection.values()); + dataDirection = createComboBox(HttpDataDirection.values()); httpMessage = createTextField(true); JButton addGetter = new JButton("Add Getter"); @@ -55,7 +56,7 @@ private JPanel getMessageValueGetterList() { boolean deletableGetter = false; for (MessageValueGetterModel messageValueGetterModel : model.getMessageValueGetters()) { messageValueGetterModel.withListener(messageValueGetterChangedListener); - messageValueGettersComponent.add(new MessageValueGetterComponent(messageValueGetterModel, model.getDataDirection(), deletableGetter), "wrap"); + messageValueGettersComponent.add(new MessageValueGetterComponent(protocolType, messageValueGetterModel, model.getDataDirection(), deletableGetter), "wrap"); deletableGetter = true; } return messageValueGettersComponent; @@ -65,7 +66,7 @@ private void onSetDataDirectionChanged(ActionEvent actionEvent) { for (MessageValueGetterModel messageValueGetterModel : new ArrayList<>(model.getMessageValueGetters())) { removeMessageValueGetter(messageValueGetterModel); } - model.setDataDirection((DataDirection) dataDirection.getSelectedItem()); + model.setDataDirection((HttpDataDirection) dataDirection.getSelectedItem()); addMessageValueGetter(); } @@ -93,7 +94,7 @@ private void addMessageValueGetter() { MessageValueGetterModel messageValueGetterModel = model.addMessageValueGetter() .withListener(messageValueGetterChangedListener); messageValueGettersComponent.add(new MessageValueGetterComponent( - messageValueGetterModel, + protocolType, messageValueGetterModel, model.getDataDirection(), deletable ), "wrap"); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenPromptComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenPromptComponent.java index 41000f7..e38f835 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenPromptComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenPromptComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenPrompt; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.ui.models.rules.thens.ThenPromptModel; @@ -16,8 +17,8 @@ public class ThenPromptComponent extends ThenComponent captureVariableSource; private JTextField captureVariableName; - public ThenPromptComponent(ThenPromptModel then) { - super(then); + public ThenPromptComponent(ProtocolType protocolType, ThenPromptModel then) { + super(protocolType, then); initComponent(); } @@ -26,7 +27,7 @@ private void initComponent() { starterText = createTextField(true); failAfter = createTextField(true); breakAfterFailure = new JCheckBox("Break After Failure"); - captureVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + captureVariableSource = createComboBox(VariableSource.getAllSettables(protocolType)); captureVariableName = createTextField(true); description.setText(model.getDescription()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunProcessComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunProcessComponent.java index f54c117..9ed5fc9 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunProcessComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunProcessComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenRunProcess; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.ui.models.rules.thens.ThenRunProcessModel; @@ -23,8 +24,8 @@ public class ThenRunProcessComponent extends ThenComponent captureVariableSource; private JTextField captureVariableName; - public ThenRunProcessComponent(ThenRunProcessModel then) { - super(then); + public ThenRunProcessComponent(ProtocolType protocolType, ThenRunProcessModel then) { + super(protocolType, then); initComponent(); } @@ -38,7 +39,7 @@ private void initComponent() { breakAfterFailure = new JCheckBox("Break After Failure"); captureOutput = new JCheckBox("Capture Output"); captureAfterFailure = new JCheckBox("Capture After Failure"); - captureVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + captureVariableSource = createComboBox(VariableSource.getAllSettables(protocolType)); captureVariableName = createTextField(true); command.setText(model.getCommand()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunRulesComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunRulesComponent.java index dde4ff4..ab92982 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunRulesComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunRulesComponent.java @@ -2,31 +2,39 @@ import burp.BurpExtender; import org.apache.commons.lang3.StringUtils; -import synfron.reshaper.burp.core.rules.RulesRegistry; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.rules.Rule; +import synfron.reshaper.burp.core.rules.RulesEngine; import synfron.reshaper.burp.core.rules.thens.ThenRunRules; import synfron.reshaper.burp.ui.models.rules.thens.ThenRunRulesModel; import synfron.reshaper.burp.ui.utils.ComponentVisibilityManager; -import synfron.reshaper.burp.ui.utils.DocumentActionListener; import javax.swing.*; import java.awt.event.ActionEvent; import java.util.Arrays; -import java.util.stream.Collectors; import java.util.stream.Stream; public class ThenRunRulesComponent extends ThenComponent { private JComboBox ruleName; private JCheckBox runSingle; - public ThenRunRulesComponent(ThenRunRulesModel then) { - super(then); + public ThenRunRulesComponent(ProtocolType protocolType, ThenRunRulesModel then) { + super(protocolType, then); initComponent(); } + private RulesEngine getRulesEngine(ProtocolType protocolType) { + return switch (protocolType) { + case Http -> BurpExtender.getHttpConnector().getRulesEngine(); + case WebSocket -> BurpExtender.getWebSocketConnector().getRulesEngine(); + default -> throw new UnsupportedOperationException("ProtocolType not supported here"); + }; + } + private void initComponent() { runSingle = new JCheckBox("Run Single"); ruleName = createComboBox(Stream.concat( - Arrays.stream(BurpExtender.getConnector().getRulesEngine().getRulesRegistry().getRules()).map(rule -> rule.getName()), + Arrays.stream(getRulesEngine(protocolType).getRulesRegistry().getRules()).map(Rule::getName), Stream.of(model.getRuleName()) ).filter(StringUtils::isNotEmpty).sorted().distinct().toArray(String[]::new)); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunScriptComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunScriptComponent.java index a0be265..27b6218 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunScriptComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenRunScriptComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.thens; import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenRunScript; import synfron.reshaper.burp.ui.models.rules.thens.ThenRunScriptModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -13,8 +14,8 @@ public class ThenRunScriptComponent extends ThenComponent encoding; private JComboBox fileExistsAction; - public ThenSaveFileComponent(ThenSaveFileModel then) { - super(then); + public ThenSaveFileComponent(ProtocolType protocolType, ThenSaveFileModel then) { + super(protocolType, then); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendMessageComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendMessageComponent.java new file mode 100644 index 0000000..a106e03 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendMessageComponent.java @@ -0,0 +1,44 @@ +package synfron.reshaper.burp.ui.components.rules.thens; + +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.WebSocketDataDirection; +import synfron.reshaper.burp.core.rules.thens.ThenSendMessage; +import synfron.reshaper.burp.ui.models.rules.thens.ThenSendMessageModel; +import synfron.reshaper.burp.ui.utils.DocumentActionListener; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class ThenSendMessageComponent extends ThenComponent { + + private JComboBox dataDirection; + private JTextField message; + + public ThenSendMessageComponent(ProtocolType protocolType, ThenSendMessageModel then) { + super(protocolType, then); + initComponent(); + } + + private void initComponent() { + dataDirection = createComboBox(WebSocketDataDirection.values()); + message = createTextField(true); + + dataDirection.setSelectedItem(model.getDataDirection()); + message.setText(model.getMessage()); + + dataDirection.addActionListener(this::onSetEventDirectionChanged); + message.getDocument().addDocumentListener(new DocumentActionListener(this::onMessageChanged)); + + mainContainer.add(getLabeledField("Event Direction", dataDirection), "wrap"); + mainContainer.add(getLabeledField("Message", message), "wrap"); + mainContainer.add(getPaddedButton(validate)); + } + + private void onSetEventDirectionChanged(ActionEvent actionEvent) { + model.setDataDirection((WebSocketDataDirection) dataDirection.getSelectedItem()); + } + + private void onMessageChanged(ActionEvent actionEvent) { + model.setMessage(message.getText()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendRequestComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendRequestComponent.java index 1ab10b8..886221a 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendRequestComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendRequestComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenSendRequest; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.ui.models.rules.thens.ThenSendRequestModel; @@ -25,8 +26,8 @@ public class ThenSendRequestComponent extends ThenComponent captureVariableSource; private JTextField captureVariableName; - public ThenSendRequestComponent(ThenSendRequestModel then) { - super(then); + public ThenSendRequestComponent(ProtocolType protocolType, ThenSendRequestModel then) { + super(protocolType, then); initComponent(); } @@ -42,7 +43,7 @@ private void initComponent() { breakAfterFailure = new JCheckBox("Break After Failure"); captureOutput = new JCheckBox("Capture Output"); captureAfterFailure = new JCheckBox("Capture After Failure"); - captureVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + captureVariableSource = createComboBox(VariableSource.getAllSettables(protocolType)); captureVariableName = createTextField(true); request.setText(model.getRequest()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java index 6912b10..f2f8beb 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSendToComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenSendTo; import synfron.reshaper.burp.core.rules.thens.entities.sendto.SendToOption; import synfron.reshaper.burp.ui.models.rules.thens.ThenSendToModel; @@ -8,6 +9,7 @@ import javax.swing.*; import java.awt.event.ActionEvent; +import java.util.Arrays; import java.util.List; public class ThenSendToComponent extends ThenComponent { @@ -20,13 +22,16 @@ public class ThenSendToComponent extends ThenComponent value != SendToOption.Spider) + .toArray(SendToOption[]::new) + ); overrideDefaults = new JCheckBox("Override Defaults"); host = createTextField(true); port = createTextField(true); @@ -96,8 +101,7 @@ private void initComponent() { getLabeledField("URL", url), List.of(overrideDefaults, sendTo), () -> overrideDefaults.isSelected() && ( - sendTo.getSelectedItem() == SendToOption.Spider || - sendTo.getSelectedItem() == SendToOption.Browser + sendTo.getSelectedItem() == SendToOption.Browser ) ), "wrap"); mainContainer.add(getPaddedButton(validate)); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetComponent.java index 36c4553..352eb2e 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.messages.MessageValueType; import synfron.reshaper.burp.core.rules.thens.ThenSet; @@ -11,6 +12,7 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; +import java.util.Arrays; import java.util.List; public abstract class ThenSetComponent

, T extends ThenSet> extends ThenComponent { @@ -27,14 +29,15 @@ public abstract class ThenSetComponent

, T extends T protected JComboBox destinationMessageValueType; protected JTextField destinationMessageValuePath; - public ThenSetComponent(P then) { - super(then); + public ThenSetComponent(ProtocolType protocolType, P then) { + super(protocolType, then); initComponent(); } private void initComponent() { useMessageValue = new JCheckBox("Use Message Value"); - sourceMessageValue = createComboBox(MessageValue.values()); + sourceMessageValue = createComboBox(Arrays.stream(MessageValue.values()) + .filter(value -> value.isGettable(protocolType)).toArray(MessageValue[]::new)); sourceIdentifier = createTextField(true); sourceIdentifierPlacement = createComboBox(GetItemPlacement.values()); sourceMessageValueType = createComboBox(MessageValueType.values()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEncodingComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEncodingComponent.java index 1d1f49a..922c24d 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEncodingComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEncodingComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.rules.thens.ThenSetEncoding; import synfron.reshaper.burp.ui.models.rules.thens.ThenSetEncodingModel; @@ -10,8 +11,8 @@ public class ThenSetEncodingComponent extends ThenComponent { private JComboBox encoding; - public ThenSetEncodingComponent(ThenSetEncodingModel then) { - super(then); + public ThenSetEncodingComponent(ProtocolType protocolType, ThenSetEncodingModel then) { + super(protocolType, then); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEventDirectionComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEventDirectionComponent.java index 4c869e2..2add4d4 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEventDirectionComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetEventDirectionComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.thens; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.rules.thens.ThenSetEventDirection; import synfron.reshaper.burp.ui.models.rules.thens.ThenSetEventDirectionModel; @@ -8,15 +9,15 @@ import java.awt.event.ActionEvent; public class ThenSetEventDirectionComponent extends ThenComponent { - private JComboBox dataDirection; + private JComboBox dataDirection; - public ThenSetEventDirectionComponent(ThenSetEventDirectionModel then) { - super(then); + public ThenSetEventDirectionComponent(ProtocolType protocolType, ThenSetEventDirectionModel then) { + super(protocolType, then); initComponent(); } private void initComponent() { - dataDirection = createComboBox(DataDirection.values()); + dataDirection = createComboBox(HttpDataDirection.values()); dataDirection.setSelectedItem(model.getDataDirection()); @@ -27,6 +28,6 @@ private void initComponent() { } private void onSetEventDirectionChanged(ActionEvent actionEvent) { - model.setDataDirection((DataDirection) dataDirection.getSelectedItem()); + model.setDataDirection((HttpDataDirection) dataDirection.getSelectedItem()); } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetValueComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetValueComponent.java index 55e5603..1c4c2dd 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetValueComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetValueComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.rules.thens.ThenSetValue; import synfron.reshaper.burp.core.utils.SetItemPlacement; @@ -10,6 +11,7 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; +import java.util.Arrays; import java.util.List; public class ThenSetValueComponent extends ThenSetComponent { @@ -18,13 +20,14 @@ public class ThenSetValueComponent extends ThenSetComponent destinationIdentifierPlacement; - public ThenSetValueComponent(ThenSetValueModel then) { - super(then); + public ThenSetValueComponent(ProtocolType protocolType, ThenSetValueModel then) { + super(protocolType, then); } @Override protected List getExtendedComponents() { - destinationMessageValue = createComboBox(MessageValue.values()); + destinationMessageValue = createComboBox(Arrays.stream(MessageValue.values()) + .filter(value -> value.isSettable(protocolType)).toArray(MessageValue[]::new)); destinationIdentifier = createTextField(true); destinationIdentifierPlacement = createComboBox(SetItemPlacement.values()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetVariableComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetVariableComponent.java index 4c39030..29086e7 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetVariableComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThenSetVariableComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenSetVariable; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.ui.models.rules.thens.ThenSetVariableModel; @@ -15,13 +16,13 @@ public class ThenSetVariableComponent extends ThenSetComponent targetSource; private JTextField variableName; - public ThenSetVariableComponent(ThenSetVariableModel then) { - super(then); + public ThenSetVariableComponent(ProtocolType protocolType, ThenSetVariableModel then) { + super(protocolType, then); } @Override protected List getExtendedComponents() { - targetSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + targetSource = createComboBox(VariableSource.getAllSettables(protocolType)); variableName = createTextField(true); targetSource.setSelectedItem(model.getTargetSource()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThensComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThensComponent.java index 6f0f236..ac45b61 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThensComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/ThensComponent.java @@ -1,19 +1,21 @@ package synfron.reshaper.burp.ui.components.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.ui.components.rules.RuleOperationListComponent; import synfron.reshaper.burp.ui.components.rules.RuleOperationsComponent; import synfron.reshaper.burp.ui.models.rules.RuleModel; import synfron.reshaper.burp.ui.models.rules.thens.ThenModel; public class ThensComponent extends RuleOperationsComponent> { - public ThensComponent(RuleModel model) { - super(model); + + public ThensComponent(ProtocolType protocolType, RuleModel model) { + super(protocolType, model); } @Override protected RuleOperationListComponent> getOperationList() { - ThenListComponent component = new ThenListComponent(model); - component.setSelectionContainer(new ThenContainerComponent()); + ThenListComponent component = new ThenListComponent(protocolType, model); + component.setSelectionContainer(new ThenContainerComponent(protocolType)); return component; } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java index 32f1ddf..afd0441 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/buildhttpmessage/MessageValueSetterComponent.java @@ -1,7 +1,8 @@ package synfron.reshaper.burp.ui.components.rules.thens.buildhttpmessage; import net.miginfocom.swing.MigLayout; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.utils.SetItemPlacement; import synfron.reshaper.burp.ui.components.IFormComponent; @@ -18,14 +19,14 @@ public class MessageValueSetterComponent extends JPanel implements IFormComponent { private final MessageValueSetterModel model; - private final DataDirection dataDirection; + private final HttpDataDirection dataDirection; private final boolean deletable; private JComboBox destinationMessageValue; private JTextField destinationIdentifier; private JComboBox destinationIdentifierPlacement; private JTextField sourceText; - public MessageValueSetterComponent(MessageValueSetterModel model, DataDirection dataDirection, boolean deletable) { + public MessageValueSetterComponent(MessageValueSetterModel model, HttpDataDirection dataDirection, boolean deletable) { this.dataDirection = dataDirection; this.deletable = deletable; setBorder(new CompoundBorder( @@ -42,7 +43,7 @@ private void initComponent() { sourceText = createTextField(true); destinationMessageValue = createComboBox( Stream.of(MessageValue.values()) - .filter(messageValue -> messageValue.getDataDirection() == dataDirection && messageValue.isMessageSettable()) + .filter(messageValue -> messageValue.getDataDirection() == dataDirection && messageValue.isInnerLevelSettable(ProtocolType.Http)) .toArray(MessageValue[]::new) ); destinationIdentifier = createTextField(true); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java index bbf6636..0a9d8ce 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/thens/parsehttpmessage/MessageValueGetterComponent.java @@ -1,7 +1,8 @@ package synfron.reshaper.burp.ui.components.rules.thens.parsehttpmessage; import net.miginfocom.swing.MigLayout; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.utils.GetItemPlacement; import synfron.reshaper.burp.core.vars.VariableSource; @@ -19,7 +20,8 @@ public class MessageValueGetterComponent extends JPanel implements IFormComponent { private final MessageValueGetterModel model; - private final DataDirection dataDirection; + private final ProtocolType protocolType; + private final HttpDataDirection dataDirection; private final boolean deletable; private JComboBox sourceMessageValue; private JTextField sourceIdentifier; @@ -27,7 +29,8 @@ public class MessageValueGetterComponent extends JPanel implements IFormComponen private JComboBox destinationVariableSource; private JTextField destinationVariableName; - public MessageValueGetterComponent(MessageValueGetterModel model, DataDirection dataDirection, boolean deletable) { + public MessageValueGetterComponent(ProtocolType protocolType, MessageValueGetterModel model, HttpDataDirection dataDirection, boolean deletable) { + this.protocolType = protocolType; this.dataDirection = dataDirection; this.deletable = deletable; setBorder(new CompoundBorder( @@ -43,12 +46,12 @@ private void initComponent() { sourceMessageValue = createComboBox( Stream.of(MessageValue.values()) - .filter(messageValue -> messageValue.getDataDirection() == dataDirection && messageValue.isMessageGettable()) + .filter(messageValue -> messageValue.getDataDirection() == dataDirection && messageValue.isInnerLevelGettable(ProtocolType.Http)) .toArray(MessageValue[]::new) ); sourceIdentifier = createTextField(true); sourceIdentifierPlacement = createComboBox(GetItemPlacement.values()); - destinationVariableSource = createComboBox(new VariableSource[] { VariableSource.Event, VariableSource.Global }); + destinationVariableSource = createComboBox(VariableSource.getAllSettables(protocolType)); destinationVariableName = createTextField(true); sourceMessageValue.setSelectedItem(model.getSourceMessageValue()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenComponent.java index 98453b7..e4278be 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.whens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.whens.When; import synfron.reshaper.burp.ui.components.rules.RuleOperationComponent; import synfron.reshaper.burp.ui.models.rules.whens.WhenModel; @@ -14,8 +15,8 @@ public abstract class WhenComponent

, T extends When protected JCheckBox useOrCondition; protected JCheckBox negate; - public WhenComponent(P model) { - super(model); + public WhenComponent(ProtocolType protocolType, P model) { + super(protocolType, model); setBorder(new CompoundBorder( BorderFactory.createTitledBorder(String.format("When %s", model.getType().getName())), BorderFactory.createEmptyBorder(4,4,4,4)) diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContainerComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContainerComponent.java index 647e779..bf04018 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContainerComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContainerComponent.java @@ -1,8 +1,8 @@ package synfron.reshaper.burp.ui.components.rules.whens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.ui.components.rules.RuleOperationContainerComponent; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; -import synfron.reshaper.burp.ui.models.rules.whens.WhenContentTypeModel; import synfron.reshaper.burp.ui.models.rules.whens.WhenModelType; import java.util.HashMap; @@ -15,15 +15,21 @@ public class WhenContainerComponent extends RuleOperationContainerComponent { static { componentMap = new HashMap<>(); componentMap.put(WhenModelType.EventDirection, WhenEventDirectionComponent.class); + componentMap.put(WhenModelType.WebSocketEventDirection, WhenWebSocketEventDirectionComponent.class); componentMap.put(WhenModelType.HasEntity, WhenHasEntityComponent.class); componentMap.put(WhenModelType.MatchesText, WhenMatchesTextComponent.class); componentMap.put(WhenModelType.ContentType, WhenContentTypeComponent.class); componentMap.put(WhenModelType.MimeType, WhenMimeTypeComponent.class); + componentMap.put(WhenModelType.MessageType, WhenMessageTypeComponent.class); componentMap.put(WhenModelType.ProxyName, WhenProxyNameComponent.class); componentMap.put(WhenModelType.FromTool, WhenFromToolComponent.class); componentMap.put(WhenModelType.InScope, WhenInScopeComponent.class); } + public WhenContainerComponent(ProtocolType protocolType) { + super(protocolType); + } + @Override protected Map, Class> getComponentMap() { return componentMap; diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContentTypeComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContentTypeComponent.java index 913a8d4..dd70579 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContentTypeComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenContentTypeComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.whens; import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.ContentType; import synfron.reshaper.burp.core.rules.whens.WhenContentType; import synfron.reshaper.burp.ui.models.rules.whens.WhenContentTypeModel; @@ -17,8 +18,8 @@ public class WhenContentTypeComponent extends WhenComponent { - private JComboBox dataDirection; + private JComboBox dataDirection; - public WhenEventDirectionComponent(WhenEventDirectionModel when) { - super(when); + public WhenEventDirectionComponent(ProtocolType protocolType, WhenEventDirectionModel when) { + super(protocolType, when); initComponent(); } private void initComponent() { - dataDirection = createComboBox(DataDirection.values()); + dataDirection = createComboBox(HttpDataDirection.values()); dataDirection.setSelectedItem(model.getDataDirection()); @@ -28,6 +29,6 @@ private void initComponent() { } private void onDataDirectionChanged(ActionEvent actionEvent) { - model.setDataDirection((DataDirection)dataDirection.getSelectedItem()); + model.setDataDirection((HttpDataDirection)dataDirection.getSelectedItem()); } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenFromToolComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenFromToolComponent.java index cd063f1..2edcc32 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenFromToolComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenFromToolComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.whens; import synfron.reshaper.burp.core.BurpTool; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.whens.WhenFromTool; import synfron.reshaper.burp.ui.models.rules.whens.WhenFromToolModel; @@ -10,8 +11,8 @@ public class WhenFromToolComponent extends WhenComponent { private JComboBox tool; - public WhenFromToolComponent(WhenFromToolModel when) { - super(when); + public WhenFromToolComponent(ProtocolType protocolType, WhenFromToolModel when) { + super(protocolType, when); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenHasEntityComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenHasEntityComponent.java index 0c2080c..7f99d7d 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenHasEntityComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenHasEntityComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.whens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.rules.whens.WhenHasEntity; import synfron.reshaper.burp.ui.models.rules.whens.WhenHasEntityModel; @@ -8,19 +9,22 @@ import javax.swing.*; import java.awt.event.ActionEvent; +import java.util.Arrays; public class WhenHasEntityComponent extends WhenComponent { private JComboBox messageValue; private JTextField identifier; - public WhenHasEntityComponent(WhenHasEntityModel when) { - super(when); + public WhenHasEntityComponent(ProtocolType protocolType, WhenHasEntityModel when) { + super(protocolType, when); initComponent(); } private void initComponent() { identifier = createTextField(true); - messageValue = createComboBox(MessageValue.values()); + messageValue = createComboBox(Arrays.stream(MessageValue.values()) + .filter(value -> value.isGettable(protocolType)) + .toArray(MessageValue[]::new)); messageValue.setSelectedItem(model.getMessageValue()); identifier.setText(model.getIdentifier()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenInScopeComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenInScopeComponent.java index 6b7987d..900d22a 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenInScopeComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenInScopeComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.whens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.whens.WhenInScope; import synfron.reshaper.burp.ui.models.rules.whens.WhenInScopeModel; import synfron.reshaper.burp.ui.utils.DocumentActionListener; @@ -10,8 +11,8 @@ public class WhenInScopeComponent extends WhenComponent { private JTextField url; - public WhenInScopeComponent(WhenInScopeModel when) { - super(when); + public WhenInScopeComponent(ProtocolType protocolType, WhenInScopeModel when) { + super(protocolType, when); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenListComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenListComponent.java index 65dd4e6..ffee4b5 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenListComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenListComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.whens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.IRuleOperation; import synfron.reshaper.burp.core.rules.whens.When; import synfron.reshaper.burp.ui.components.rules.RuleOperationListComponent; @@ -13,8 +14,8 @@ public class WhenListComponent extends RuleOperationListComponent> { - public WhenListComponent(RuleModel model) { - super(model); + public WhenListComponent(ProtocolType protocolType, RuleModel model) { + super(protocolType, model); } @Override @@ -24,16 +25,16 @@ public WhenListComponent(RuleModel model) { @Override protected List> getRuleOperationModelTypes() { - return Collections.unmodifiableList(WhenModelType.getTypes()); + return Collections.unmodifiableList(WhenModelType.getTypes(protocolType)); } @Override protected WhenModel getNewModel(RuleOperationModelType ruleOperationModelType) { - return WhenModel.getNewModel(ruleOperationModelType); + return WhenModel.getNewModel(protocolType, ruleOperationModelType); } @Override protected > WhenModel getModel(R when) { - return WhenModel.getModel((When)when); + return WhenModel.getModel(protocolType, (When)when); } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMatchesTextComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMatchesTextComponent.java index bb964b3..9e2a49c 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMatchesTextComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMatchesTextComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.whens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.messages.MessageValueType; import synfron.reshaper.burp.core.rules.MatchType; @@ -11,6 +12,7 @@ import javax.swing.*; import java.awt.event.ActionEvent; +import java.util.Arrays; import java.util.List; public class WhenMatchesTextComponent extends WhenComponent { @@ -22,16 +24,19 @@ public class WhenMatchesTextComponent extends WhenComponent matchType; - public WhenMatchesTextComponent(WhenMatchesTextModel when) { - super(when); + public WhenMatchesTextComponent(ProtocolType protocolType, WhenMatchesTextModel when) { + super(protocolType, when); initComponent(); } private void initComponent() { useMessageValue = new JCheckBox("Use Message Value"); - messageValue = createComboBox(MessageValue.values()); + messageValue = createComboBox(Arrays.stream(MessageValue.values()) + .filter(value -> value.isGettable(protocolType)) + .toArray(MessageValue[]::new)); identifier = createTextField(true); identifierPlacement = createComboBox(GetItemPlacement.values()); sourceText = createTextField(true); @@ -39,6 +44,7 @@ private void initComponent() { messageValuePath = createTextField(true); matchType = createComboBox(MatchType.values()); matchText = createTextField(true); + ignoreCase = new JCheckBox("Ignore Case"); useMessageValue.setSelected(model.isUseMessageValue()); messageValue.setSelectedItem(model.getMessageValue()); @@ -49,6 +55,7 @@ private void initComponent() { messageValuePath.setText(model.getMessageValuePath()); matchType.setSelectedItem(model.getMatchType()); matchText.setText(model.getMatchText()); + ignoreCase.setSelected(model.isIgnoreCase()); useMessageValue.addActionListener(this::onUseMessageValueChanged); messageValue.addActionListener(this::onMessageValueChanged); @@ -59,6 +66,7 @@ private void initComponent() { messageValuePath.getDocument().addDocumentListener(new DocumentActionListener(this::onMessageValuePathChanged)); matchType.addActionListener(this::onMatchTypeChanged); matchText.getDocument().addDocumentListener(new DocumentActionListener(this::onMatchTextChanged)); + ignoreCase.addActionListener(this::onIgnoreCaseChanged); mainContainer.add(useMessageValue, "wrap"); mainContainer.add(ComponentVisibilityManager.withVisibilityFieldChangeDependency( @@ -89,6 +97,7 @@ private void initComponent() { ), "wrap"); mainContainer.add(getLabeledField("Match Type", matchType), "wrap"); mainContainer.add(getLabeledField("Match Text", matchText), "wrap"); + mainContainer.add(ignoreCase, "wrap"); getDefaultComponents().forEach(component -> mainContainer.add(component, "wrap")); mainContainer.add(getPaddedButton(validate)); } @@ -128,4 +137,8 @@ private void onSourceTextChanged(ActionEvent actionEvent) { private void onMatchTextChanged(ActionEvent actionEvent) { model.setMatchText(matchText.getText()); } + + private void onIgnoreCaseChanged(ActionEvent actionEvent) { + model.setIgnoreCase(ignoreCase.isSelected()); + } } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMessageTypeComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMessageTypeComponent.java new file mode 100644 index 0000000..bad1017 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMessageTypeComponent.java @@ -0,0 +1,34 @@ +package synfron.reshaper.burp.ui.components.rules.whens; + +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.WebSocketMessageType; +import synfron.reshaper.burp.core.rules.whens.WhenMessageType; +import synfron.reshaper.burp.ui.models.rules.whens.WhenMessageTypeModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class WhenMessageTypeComponent extends WhenComponent { + private JComboBox messageType; + + public WhenMessageTypeComponent(ProtocolType protocolType, WhenMessageTypeModel when) { + super(protocolType, when); + initComponent(); + } + + private void initComponent() { + messageType = createComboBox(WebSocketMessageType.values()); + + messageType.setSelectedItem(model.getMessageType()); + + messageType.addActionListener(this::onMessageTypeChanged); + + mainContainer.add(getLabeledField("Message Type", messageType), "wrap"); + getDefaultComponents().forEach(component -> mainContainer.add(component, "wrap")); + mainContainer.add(getPaddedButton(validate)); + } + + private void onMessageTypeChanged(ActionEvent actionEvent) { + model.setMessageType((WebSocketMessageType)messageType.getSelectedItem()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMimeTypeComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMimeTypeComponent.java index b03f284..47e182f 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMimeTypeComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenMimeTypeComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.whens; import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MimeType; import synfron.reshaper.burp.core.rules.whens.WhenMimeType; import synfron.reshaper.burp.ui.models.rules.whens.WhenMimeTypeModel; @@ -20,8 +21,8 @@ public class WhenMimeTypeComponent extends WhenComponent { private JTextField proxyName; - public WhenProxyNameComponent(WhenProxyNameModel when) { - super(when); + public WhenProxyNameComponent(ProtocolType protocolType, WhenProxyNameModel when) { + super(protocolType, when); initComponent(); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenWebSocketEventDirectionComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenWebSocketEventDirectionComponent.java new file mode 100644 index 0000000..fdbab45 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhenWebSocketEventDirectionComponent.java @@ -0,0 +1,34 @@ +package synfron.reshaper.burp.ui.components.rules.whens; + +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.WebSocketDataDirection; +import synfron.reshaper.burp.core.rules.whens.WhenWebSocketEventDirection; +import synfron.reshaper.burp.ui.models.rules.whens.WhenWebSocketEventDirectionModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class WhenWebSocketEventDirectionComponent extends WhenComponent { + private JComboBox dataDirection; + + public WhenWebSocketEventDirectionComponent(ProtocolType protocolType, WhenWebSocketEventDirectionModel when) { + super(protocolType, when); + initComponent(); + } + + private void initComponent() { + dataDirection = createComboBox(WebSocketDataDirection.values()); + + dataDirection.setSelectedItem(model.getDataDirection()); + + dataDirection.addActionListener(this::onDataDirectionChanged); + + mainContainer.add(getLabeledField("Event Direction", dataDirection), "wrap"); + getDefaultComponents().forEach(component -> mainContainer.add(component, "wrap")); + mainContainer.add(getPaddedButton(validate)); + } + + private void onDataDirectionChanged(ActionEvent actionEvent) { + model.setDataDirection((WebSocketDataDirection)dataDirection.getSelectedItem()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhensComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhensComponent.java index b23793d..6ed0314 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhensComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/whens/WhensComponent.java @@ -1,19 +1,21 @@ package synfron.reshaper.burp.ui.components.rules.whens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.ui.components.rules.RuleOperationListComponent; import synfron.reshaper.burp.ui.components.rules.RuleOperationsComponent; import synfron.reshaper.burp.ui.models.rules.RuleModel; import synfron.reshaper.burp.ui.models.rules.whens.WhenModel; public class WhensComponent extends RuleOperationsComponent> { - public WhensComponent(RuleModel model) { - super(model); + + public WhensComponent(ProtocolType protocolType, RuleModel model) { + super(protocolType, model); } @Override protected RuleOperationListComponent> getOperationList() { - WhenListComponent component = new WhenListComponent(model); - component.setSelectionContainer(new WhenContainerComponent()); + WhenListComponent component = new WhenListComponent(protocolType, model); + component.setSelectionContainer(new WhenContainerComponent(protocolType)); return component; } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/AnnotationVariableTagWizardComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/AnnotationVariableTagWizardComponent.java new file mode 100644 index 0000000..a4018cc --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/AnnotationVariableTagWizardComponent.java @@ -0,0 +1,35 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.messages.MessageAnnotation; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.AnnotationVariableTagWizardModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class AnnotationVariableTagWizardComponent extends JPanel implements IFormComponent { + private final AnnotationVariableTagWizardModel model; + private JComboBox messageAnnotation; + + public AnnotationVariableTagWizardComponent(AnnotationVariableTagWizardModel model) { + this.model = model; + initComponent(); + } + + private void initComponent() { + setLayout(new MigLayout()); + + messageAnnotation = createComboBox(MessageAnnotation.values()); + + messageAnnotation.setSelectedItem(model.getMessageAnnotation()); + + messageAnnotation.addActionListener(this::onMessageAnnotationChanged); + + add(getLabeledField("Annotation", messageAnnotation), "wrap"); + } + + private void onMessageAnnotationChanged(ActionEvent actionEvent) { + model.setMessageAnnotation((MessageAnnotation)messageAnnotation.getSelectedItem()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java index 7c7650c..034c395 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/MessageVariableTagWizardComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.wizard.vars; import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.ui.components.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.vars.MessageVariableTagWizardModel; @@ -9,21 +10,26 @@ import javax.swing.*; import java.awt.event.ActionEvent; +import java.util.Arrays; public class MessageVariableTagWizardComponent extends JPanel implements IFormComponent { private final MessageVariableTagWizardModel model; + private final ProtocolType protocolType; private JComboBox messageValue; private JTextField identifier; - public MessageVariableTagWizardComponent(MessageVariableTagWizardModel model) { + public MessageVariableTagWizardComponent(MessageVariableTagWizardModel model, ProtocolType protocolType) { this.model = model; + this.protocolType = protocolType; initComponent(); } private void initComponent() { setLayout(new MigLayout()); - messageValue = createComboBox(MessageValue.values()); + messageValue = createComboBox(Arrays.stream(MessageValue.values()) + .filter(value -> value.isGettable(protocolType)) + .toArray(MessageValue[]::new)); identifier = createTextField(true); messageValue.setSelectedItem(model.getMessageValue()); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SessionVariableTagWizardComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SessionVariableTagWizardComponent.java new file mode 100644 index 0000000..6136504 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/SessionVariableTagWizardComponent.java @@ -0,0 +1,34 @@ +package synfron.reshaper.burp.ui.components.rules.wizard.vars; + +import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.ui.components.IFormComponent; +import synfron.reshaper.burp.ui.models.rules.wizard.vars.SessionVariableTagWizardModel; + +import javax.swing.*; +import java.awt.event.ActionEvent; + +public class SessionVariableTagWizardComponent extends JPanel implements IFormComponent { + private final SessionVariableTagWizardModel model; + private JComboBox variableName; + + public SessionVariableTagWizardComponent(SessionVariableTagWizardModel model) { + this.model = model; + initComponent(); + } + + private void initComponent() { + setLayout(new MigLayout()); + + variableName = createComboBox(model.getVariableNames().toArray(new String[0]), true); + + variableName.setSelectedItem(model.getVariableNames().stream().findFirst().orElse("")); + + variableName.addActionListener(this::onVariableNameChanged); + + add(getLabeledField("Variable Name *", variableName)); + } + + private void onVariableNameChanged(ActionEvent actionEvent) { + model.setVariableName((String)variableName.getSelectedItem()); + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java index 158715d..1eb4ad0 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardContainerComponent.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.wizard.vars; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.ui.models.rules.wizard.vars.*; import javax.swing.*; @@ -7,7 +8,10 @@ public class VariableTagWizardContainerComponent extends JPanel { - public VariableTagWizardContainerComponent() { + private final ProtocolType protocolType; + + public VariableTagWizardContainerComponent(ProtocolType protocolType) { + this.protocolType = protocolType; initComponent(); } @@ -21,7 +25,9 @@ public void setModel(IVariableTagWizardModel model) { JPanel component = switch (model.getVariableSource()) { case Event -> new EventVariableTagWizardComponent((EventVariableTagWizardModel) model); case Global -> new GlobalVariableTagWizardComponent((GlobalVariableTagWizardModel) model); - case Message -> new MessageVariableTagWizardComponent((MessageVariableTagWizardModel) model); + case Session -> new SessionVariableTagWizardComponent((SessionVariableTagWizardModel) model); + case Message -> new MessageVariableTagWizardComponent((MessageVariableTagWizardModel) model, protocolType); + case Annotation -> new AnnotationVariableTagWizardComponent((AnnotationVariableTagWizardModel) model); case File -> new FileVariableTagWizardComponent((FileVariableTagWizardModel) model); case Special -> new SpecialVariableTagWizardComponent((SpecialVariableTagWizardModel) model); case CookieJar -> new CookieJarVariableTagWizardComponent((CookieJarVariableTagWizardModel) model); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java index a3c59f0..7582697 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/vars/VariableTagWizardOptionPane.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.components.rules.wizard.vars; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.ui.components.IFormComponent; @@ -17,13 +18,16 @@ public class VariableTagWizardOptionPane extends JOptionPane implements IFormCom private final JPanel outerContainer; private final VariableTagWizardModel model; private JComboBox variableSource; - private final VariableTagWizardContainerComponent container = new VariableTagWizardContainerComponent(); + private final VariableTagWizardContainerComponent container; private JDialog currentDialog; + private final ProtocolType protocolType; - private VariableTagWizardOptionPane(VariableTagWizardModel model) { + private VariableTagWizardOptionPane(VariableTagWizardModel model, ProtocolType protocolType) { super(new JPanel(new BorderLayout()), JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION); + container = new VariableTagWizardContainerComponent(protocolType); outerContainer = (JPanel)message; this.model = model; + this.protocolType = protocolType; addPropertyChangeListener(JOptionPane.VALUE_PROPERTY, this::onPropertyChanged); initComponent(); @@ -31,7 +35,7 @@ private VariableTagWizardOptionPane(VariableTagWizardModel model) { } private void initComponent() { - variableSource = createComboBox(VariableSource.values()); + variableSource = createComboBox(VariableSource.getAll(protocolType)); variableSource.setSelectedItem(model.getVariableSource()); @@ -83,8 +87,8 @@ private void onPropertyChanged(PropertyChangeEvent event) { } } - public static void showDialog(VariableTagWizardModel model) { - VariableTagWizardOptionPane optionPane = new VariableTagWizardOptionPane(model); + public static void showDialog(VariableTagWizardModel model, ProtocolType protocolType) { + VariableTagWizardOptionPane optionPane = new VariableTagWizardOptionPane(model, protocolType); JDialog dialog = optionPane.createDialog("Variable Tag"); optionPane.setCurrentDialog(dialog); dialog.setVisible(true); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java index 8298e33..3260532 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/rules/wizard/whens/WhenWizardItemComponent.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.components.rules.wizard.whens; import net.miginfocom.swing.MigLayout; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.ui.components.IFormComponent; import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardItemModel; @@ -11,6 +12,7 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; +import java.util.Arrays; import java.util.List; public class WhenWizardItemComponent extends JPanel implements IFormComponent { @@ -31,7 +33,8 @@ private void initComponent() { setLayout(new BorderLayout()); JPanel container = new JPanel(new MigLayout()); - messageValue = createComboBox(MessageValue.values()); + messageValue = createComboBox(Arrays.stream(MessageValue.values()) + .filter(value -> value.isGettable(ProtocolType.Http)).toArray(MessageValue[]::new)); identifier = createComboBox(model.getIdentifiers().getOptions().toArray(new String[0])); matchType = createComboBox(WhenWizardMatchType.values()); text = createTextField(true); diff --git a/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java index 848e153..fbb1332 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/settings/SettingsTabComponent.java @@ -4,6 +4,7 @@ import com.alexandriasoftware.swing.JSplitButton; import net.miginfocom.swing.MigLayout; import org.apache.commons.io.IOUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.rules.Rule; import synfron.reshaper.burp.core.settings.GeneralSettings; @@ -28,6 +29,7 @@ import java.net.URL; import java.net.URLConnection; import java.nio.charset.Charset; +import java.util.Arrays; import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -35,9 +37,9 @@ public class SettingsTabComponent extends JPanel implements IFormComponent { private JCheckBox overwriteDuplicates; - private DefaultTableModel exportRulesModel; + private DefaultTableModel exportHttpRulesModel; + private DefaultTableModel exportWebSocketRulesModel; private DefaultTableModel exportVariablesModel; - private final SettingsManager settingsManager = BurpExtender.getConnector().getSettingsManager(); private final GeneralSettings generalSettings = BurpExtender.getGeneralSettings(); private JCheckBox enableEventDiagnostics; private JTextField diagnosticValueMaxLength; @@ -49,10 +51,11 @@ public class SettingsTabComponent extends JPanel implements IFormComponent { private JCheckBox repeater; private JCheckBox intruder; private JCheckBox scanner; - private JCheckBox spider; private JCheckBox target; private JCheckBox extender; + private JCheckBox webSockets; private ButtonGroup importMethod; + private ButtonGroup exportMethod; public SettingsTabComponent() { initComponent(); @@ -123,34 +126,34 @@ private Component getCaptureTrafficOptions() { repeater = new JCheckBox("Repeater"); intruder = new JCheckBox("Intruder"); scanner = new JCheckBox("Scanner"); - spider = new JCheckBox("Spider"); target = new JCheckBox("Target"); extender = new JCheckBox("Extender"); + webSockets = new JCheckBox("WebSockets"); proxy.setSelected(generalSettings.isCaptureProxy()); repeater.setSelected(generalSettings.isCaptureRepeater()); intruder.setSelected(generalSettings.isCaptureIntruder()); scanner.setSelected(generalSettings.isCaptureScanner()); - spider.setSelected(generalSettings.isCaptureSpider()); target.setSelected(generalSettings.isCaptureTarget()); extender.setSelected(generalSettings.isCaptureExtender()); + webSockets.setSelected(generalSettings.isCaptureWebSockets()); proxy.addActionListener(this::onProxyChanged); repeater.addActionListener(this::onRepeaterChanged); intruder.addActionListener(this::onIntruderChanged); scanner.addActionListener(this::onScannerChanged); - spider.addActionListener(this::onSpiderChanged); target.addActionListener(this::onTargetChanged); extender.addActionListener(this::onExtenderChanged); + webSockets.addActionListener(this::onWebSocketsChanged); container.add(new JLabel("Capture Traffic From:"), "wrap"); container.add(proxy); container.add(repeater, "wrap"); container.add(intruder); container.add(scanner, "wrap"); - container.add(spider); - container.add(target, "wrap"); - container.add(extender); + container.add(target); + container.add(extender, "wrap"); + container.add(webSockets); return container; } @@ -158,7 +161,7 @@ private void onResetData(ActionEvent actionEvent) { try { int response = JOptionPane.showConfirmDialog(this, "Are you sure you want to reset data? This will remove all rules and variables.", "Reset Data", JOptionPane.YES_NO_OPTION); if (response == JOptionPane.YES_OPTION) { - settingsManager.resetData(); + SettingsManager.resetData(); refreshLists(); } } catch (Exception e) { @@ -216,10 +219,6 @@ private void onScannerChanged(ActionEvent actionEvent) { generalSettings.setCaptureScanner(scanner.isSelected()); } - private void onSpiderChanged(ActionEvent actionEvent) { - generalSettings.setCaptureSpider(spider.isSelected()); - } - private void onTargetChanged(ActionEvent actionEvent) { generalSettings.setCaptureTarget(target.isSelected()); } @@ -228,6 +227,10 @@ private void onExtenderChanged(ActionEvent actionEvent) { generalSettings.setCaptureExtender(extender.isSelected()); } + private void onWebSocketsChanged(ActionEvent actionEvent) { + generalSettings.setCaptureWebSockets(webSockets.isSelected()); + } + private Component getExportSettings() { JPanel container = new JPanel(new MigLayout()); container.setBorder(new CompoundBorder( @@ -242,7 +245,8 @@ private Component getExportSettings() { exportData.addActionListener(this::onExportData); container.add(new JLabel("Items to Export"), "wrap"); - container.add(getExportRulesTable()); + container.add(getExportHttpRulesTable()); + container.add(getExportWebSocketRulesTable()); container.add(getExportVariablesTable(), "wrap"); container.add(getExportActions()); return container; @@ -252,16 +256,44 @@ private Component getExportActions() { JPanel container = new JPanel(new FlowLayout(FlowLayout.LEFT)); JButton refresh = new JButton("Refresh Lists"); - JButton exportData = new JButton("Export Data"); + JButton exportData = getExportDataButton(); refresh.addActionListener(this::onRefresh); - exportData.addActionListener(this::onExportData); container.add(refresh); container.add(exportData); return container; } + + private JSplitButton getExportDataButton() { + JSplitButton exportData = new JSplitButton("Export Data "); + + JPopupMenu exportOptions = new JPopupMenu(); + + exportMethod = new ButtonGroup(); + JRadioButtonMenuItem exportFromJson = new JRadioButtonMenuItem("To JSON"); + JRadioButtonMenuItem exportFromYaml = new JRadioButtonMenuItem("To YAML"); + + exportFromJson.setSelected(generalSettings.getExportMethod() == GeneralSettings.ExportMethod.Json); + exportFromJson.setActionCommand(GeneralSettings.ExportMethod.Json.name()); + exportFromYaml.setSelected(generalSettings.getExportMethod() == GeneralSettings.ExportMethod.Yaml); + exportFromYaml.setActionCommand(GeneralSettings.ExportMethod.Yaml.name()); + + exportData.addButtonClickedActionListener(this::onExportData); + exportFromYaml.addItemListener(this::onExportMethodChange); + + exportMethod.add(exportFromJson); + exportMethod.add(exportFromYaml); + + exportOptions.add(exportFromJson); + exportOptions.add(exportFromYaml); + + exportData.setPopupMenu(exportOptions); + + return exportData; + } + private Component getImportSettings() { JPanel container = new JPanel(new MigLayout()); container.setBorder(new CompoundBorder( @@ -309,8 +341,15 @@ private void onImportMethodChange(ItemEvent itemEvent) { generalSettings.setImportMethod(GeneralSettings.ImportMethod.valueOf(importMethod.getSelection().getActionCommand())); } - private JFileChooser createFileChooser(String title) { - FileNameExtensionFilter fileFiler = new FileNameExtensionFilter("JSON backup file", "json"); + + private JFileChooser createFileChooser(String title, GeneralSettings.ExportMethod... allowedFileTypes) { + FileNameExtensionFilter fileFiler = new FileNameExtensionFilter( + Arrays.stream(allowedFileTypes) + .map(type -> type.name().toUpperCase()) + .collect(Collectors.joining("/")) + " backup file", Arrays.stream(allowedFileTypes) + .map(type -> type.name().toLowerCase()) + .toArray(String[]::new) + ); JFileChooser fileChooser = new JFileChooser(); fileChooser.setDialogTitle(title); fileChooser.setAcceptAllFileFilterUsed(false); @@ -320,19 +359,31 @@ private JFileChooser createFileChooser(String title) { return fileChooser; } + private void onExportMethodChange(ItemEvent itemEvent) { + generalSettings.setExportMethod(GeneralSettings.ExportMethod.valueOf(exportMethod.getSelection().getActionCommand())); + } + private void onExportData(ActionEvent actionEvent) { try { - JFileChooser fileChooser = createFileChooser("Export"); - fileChooser.setSelectedFile(new File("~/ReshaperBackup.json")); + String extension = switch (generalSettings.getExportMethod()) { + case Json -> ".json"; + case Yaml -> ".yaml"; + }; + JFileChooser fileChooser = createFileChooser("Export", generalSettings.getExportMethod()); + fileChooser.setSelectedFile(new File("~/ReshaperBackup" + extension)); int result = fileChooser.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { - settingsManager.exportSettings( + SettingsManager.exportSettings( fileChooser.getSelectedFile(), exportVariablesModel.getDataVector().stream() .filter(row -> (boolean)row.get(0)) .map(row -> (Variable)row.get(1)) .collect(Collectors.toList()), - exportRulesModel.getDataVector().stream() + exportHttpRulesModel.getDataVector().stream() + .filter(row -> (boolean)row.get(0)) + .map(row -> (Rule)row.get(1)) + .collect(Collectors.toList()), + exportWebSocketRulesModel.getDataVector().stream() .filter(row -> (boolean)row.get(0)) .map(row -> (Rule)row.get(1)) .collect(Collectors.toList()) @@ -365,11 +416,11 @@ private void onImportData(ActionEvent actionEvent) { private void onImportFromFile() { String file = null; try { - JFileChooser fileChooser = createFileChooser("Import"); + JFileChooser fileChooser = createFileChooser("Import", GeneralSettings.ExportMethod.Json, GeneralSettings.ExportMethod.Yaml); int result = fileChooser.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { file = fileChooser.getSelectedFile().getAbsolutePath(); - settingsManager.importSettings(fileChooser.getSelectedFile(), overwriteDuplicates.isSelected()); + SettingsManager.importSettings(fileChooser.getSelectedFile(), overwriteDuplicates.isSelected()); refreshLists(); JOptionPane.showMessageDialog(this, @@ -399,7 +450,7 @@ private void onImportFromUrl() { connection.setConnectTimeout(10000); connection.setReadTimeout(10000); String settingsJson = IOUtils.toString(connection.getInputStream(), Charset.defaultCharset()); - settingsManager.importSettings(settingsJson, overwriteDuplicates.isSelected()); + SettingsManager.importSettings(settingsJson, overwriteDuplicates.isSelected()); refreshLists(); JOptionPane.showMessageDialog(this, @@ -420,13 +471,17 @@ private void onImportFromUrl() { } private void refreshLists() { - for (int row = exportRulesModel.getRowCount() - 1; row >= 0; row--) { - exportRulesModel.removeRow(row); + for (int row = exportHttpRulesModel.getRowCount() - 1; row >= 0; row--) { + exportHttpRulesModel.removeRow(row); + } + for (int row = exportWebSocketRulesModel.getRowCount() - 1; row >= 0; row--) { + exportWebSocketRulesModel.removeRow(row); } for (int row = exportVariablesModel.getRowCount() - 1; row >= 0; row--) { exportVariablesModel.removeRow(row); } - Stream.of(getExportRulesData()).forEach(row -> exportRulesModel.addRow(row)); + Stream.of(getExportHttpRulesData()).forEach(row -> exportHttpRulesModel.addRow(row)); + Stream.of(getExportWebSocketRulesData()).forEach(row -> exportWebSocketRulesModel.addRow(row)); Stream.of(getExportVariablesData()).forEach(row -> exportVariablesModel.addRow(row)); } @@ -434,7 +489,21 @@ private void onRefresh(ActionEvent actionEvent) { refreshLists(); } - private Component getExportRulesTable() { + private Component getExportHttpRulesTable() { + JTable exportRulesTable = new JTable() { + @Override + public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { + } + }; + exportRulesTable.setDefaultRenderer(Object.class, new TableCellRenderer()); + JScrollPane scrollPane = new JScrollPane(exportRulesTable); + exportHttpRulesModel = createTableModel(getExportHttpRulesData(), new Object[] { "Export", "HTTP Rule Name" }); + exportRulesTable.setModel(exportHttpRulesModel); + exportRulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + return scrollPane; + } + + private Component getExportWebSocketRulesTable() { JTable exportRulesTable = new JTable() { @Override public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { @@ -442,8 +511,8 @@ public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boole }; exportRulesTable.setDefaultRenderer(Object.class, new TableCellRenderer()); JScrollPane scrollPane = new JScrollPane(exportRulesTable); - exportRulesModel = createTableModel(getExportRulesData(), new Object[] { "Export", "Rule Name" }); - exportRulesTable.setModel(exportRulesModel); + exportWebSocketRulesModel = createTableModel(getExportWebSocketRulesData(), new Object[] { "Export", "WebSocket Rule Name" }); + exportRulesTable.setModel(exportWebSocketRulesModel); exportRulesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); return scrollPane; } @@ -474,8 +543,14 @@ public Class getColumnClass(int columnIndex) { }; } - private Object[][] getExportRulesData() { - return BurpExtender.getConnector().getRulesEngine().getRulesRegistry().exportRules().stream() + private Object[][] getExportHttpRulesData() { + return BurpExtender.getRulesRegistry(ProtocolType.Http).exportRules().stream() + .map(rule -> new Object[] { true, rule }) + .toArray(Object[][]::new); + } + + private Object[][] getExportWebSocketRulesData() { + return BurpExtender.getRulesRegistry(ProtocolType.WebSocket).exportRules().stream() .map(rule -> new Object[] { true, rule }) .toArray(Object[][]::new); } diff --git a/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java b/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java index bb90ad7..6302c27 100644 --- a/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java +++ b/src/main/java/synfron/reshaper/burp/ui/components/vars/VariableComponent.java @@ -121,7 +121,7 @@ private Component getActionBar() { } private Component getGitHubLink() { - JLabel githubLink = new JLabel("Help"); + JLabel githubLink = new JLabel("Help | View on GitHub"); githubLink.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 0)); Font font = githubLink.getFont(); Map attributes = font.getAttributes(); @@ -130,6 +130,18 @@ private Component getGitHubLink() { githubLink.addMouseListener(new MouseListener() { private final Color originalColor = githubLink.getForeground(); + private Color hoverColor; + + private Color getHoverColor() { + if (hoverColor == null) { + int halfByte = 128; + int newRed = (halfByte + originalColor.getRed()) / 2; + int newGreen = (halfByte + originalColor.getGreen()) / 2; + int newBlue = (halfByte + originalColor.getBlue()) / 2; + hoverColor = new Color(newRed, newGreen, newBlue); + } + return hoverColor; + } @SneakyThrows @Override @@ -145,7 +157,7 @@ public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) { - githubLink.setForeground(new Color(0, 0, 0xC0)); + githubLink.setForeground(getHoverColor()); } @Override diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java index f5b6eaf..55d291f 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; @@ -26,31 +27,40 @@ public class RuleModel { @Getter private boolean autoRun; @Getter + private boolean isNew; + @Getter private String name; @Getter private final List> whens; @Getter private final List> thens; @Getter + private boolean diagnosticsEnabled; + @Getter private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); private final IEventListener ruleOperationChangedListener = this::onRuleOperationChanged; + private final IEventListener ruleChangedListener = this::onRuleChanged; - public RuleModel(Rule rule) { - this(rule, false); + public RuleModel(ProtocolType protocolType, Rule rule) { + this(protocolType, rule, false); } - public RuleModel(Rule rule, boolean isNew) { + public RuleModel(ProtocolType protocolType, Rule rule, boolean isNew) { + this.isNew = isNew; this.rule = rule; this.whens = Stream.of(rule.getWhens()) - .map(when -> WhenModel.getModel(when).withListener(ruleOperationChangedListener)) + .map(when -> WhenModel.getModel(protocolType, when).withListener(ruleOperationChangedListener)) .collect(Collectors.toList()); this.thens = Stream.of(rule.getThens()) - .map(then -> ThenModel.getModel(then).withListener(ruleOperationChangedListener)) + .map(then -> ThenModel.getModel(protocolType, then).withListener(ruleOperationChangedListener)) .collect(Collectors.toList()); this.name = rule.getName(); this.enabled = rule.isEnabled(); this.autoRun = rule.isAutoRun(); + this.diagnosticsEnabled = rule.isDiagnosticsEnabled(); this.saved = !isNew; + + rule.withListener(ruleChangedListener); } private void onRuleOperationChanged(PropertyChangedArgs args) { @@ -59,6 +69,13 @@ private void onRuleOperationChanged(PropertyChangedArgs args) { } } + private void onRuleChanged(PropertyChangedArgs args) { + if (args.getName().equals("diagnosticsEnabled")) { + diagnosticsEnabled = rule.isDiagnosticsEnabled(); + propertyChangedEvent.invoke(new PropertyChangedArgs(this, "diagnosticsEnabled", diagnosticsEnabled)); + } + } + public RuleModel withListener(IEventListener listener) { propertyChangedEvent.add(listener); return this; @@ -87,6 +104,7 @@ private void propertyChanged(String name, Object value) { public void setSaved(boolean saved) { if (saved != this.saved) { this.saved = saved; + this.isNew = !saved && this.isNew; propertyChangedEvent.invoke(new PropertyChangedArgs(this, "saved", saved)); } } @@ -109,8 +127,7 @@ public List validate() { errors.addAll(thens.stream() .flatMap(model -> model.validate().stream() .map(error -> String.format("%s: %s", model.getRuleOperation().getType().getName(), error)) - ) - .collect(Collectors.toList()) + ).collect(Collectors.toList()) ); return errors; } @@ -143,6 +160,6 @@ public boolean persist() { @Override public String toString() { - return StringUtils.defaultIfEmpty(name, "untitled") + (saved ? "" : " *"); + return StringUtils.defaultIfEmpty(name, "untitled") + (saved ? "" : " *") + (diagnosticsEnabled ? " (Debug)" : ""); } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModel.java index 412b224..098c7ff 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModel.java @@ -1,6 +1,8 @@ package synfron.reshaper.burp.ui.models.rules; import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; import synfron.reshaper.burp.core.rules.IRuleOperation; @@ -9,14 +11,18 @@ import java.util.List; public abstract class RuleOperationModel

, T extends IRuleOperation> { + @Getter + protected final ProtocolType protocolType; @Getter protected final T ruleOperation; @Getter protected boolean validated; + private String validatedTarget; @Getter private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); - public RuleOperationModel(T ruleOperation, boolean isNew) { + public RuleOperationModel(ProtocolType protocolType, T ruleOperation, boolean isNew) { + this.protocolType = protocolType; this.ruleOperation = ruleOperation; this.validated = !isNew; } @@ -28,6 +34,7 @@ public List validate() { protected void setValidated(boolean validated) { if (validated != this.validated) { this.validated = validated; + resolveValidatedTarget(); propertyChangedEvent.invoke(new PropertyChangedArgs(this, "validated", validated)); } } @@ -41,9 +48,32 @@ protected void propertyChanged(String name, Object value) { public abstract boolean record(); + protected String getTargetName() { + return ""; + } + + protected String abbreviateTargetName(String text) { + return StringUtils.abbreviate(StringUtils.defaultString(text), 36); + } + + private String resolveValidatedTarget() { + if (validated) { + try { + validatedTarget = getTargetName(); + } catch (Exception ignored) { + validatedTarget = ""; + } + } else { + validatedTarget = ""; + } + return validatedTarget; + } + @Override public String toString() { - return ruleOperation.getType().getName() + (validated ? "" : " *"); + String target = resolveValidatedTarget(); + target = StringUtils.isEmpty(target) ? "" : ": " + target; + return ruleOperation.getType().getName() + target + (validated ? "" : " *"); } public abstract RuleOperationModelType getType(); diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModelType.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModelType.java index 84d806b..9b8f62b 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModelType.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/RuleOperationModelType.java @@ -1,25 +1,37 @@ package synfron.reshaper.burp.ui.models.rules; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.rules.IHttpRuleOperation; import synfron.reshaper.burp.core.rules.IRuleOperation; +import synfron.reshaper.burp.core.rules.IWebSocketRuleOperation; import synfron.reshaper.burp.core.rules.RuleOperationType; public class RuleOperationModelType

, T extends IRuleOperation> { - @Getter - private final String name; @Getter private final Class

type; @Getter private final RuleOperationType ruleOperationType; - protected RuleOperationModelType(String name, Class

type, RuleOperationType ruleOperationType) { - this.name = name; + protected RuleOperationModelType(Class

type, RuleOperationType ruleOperationType) { this.type = type; this.ruleOperationType = ruleOperationType; } + public String getName() { + return ruleOperationType.getName(); + } + @Override public String toString() { - return name; + return getName(); + } + + public boolean hasProtocolType(ProtocolType protocolType) { + return switch (protocolType) { + case Any -> true; + case Http -> IHttpRuleOperation.class.isAssignableFrom(ruleOperationType.getType()); + case WebSocket -> IWebSocketRuleOperation.class.isAssignableFrom(ruleOperationType.getType()); + }; } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBreakModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBreakModel.java index 689c58b..d47a2d1 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBreakModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBreakModel.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.models.rules.thens; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.RuleResponse; import synfron.reshaper.burp.core.rules.thens.ThenBreak; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -10,8 +11,8 @@ public class ThenBreakModel extends ThenModel { @Getter private RuleResponse breakType; - public ThenBreakModel(ThenBreak then, Boolean isNew) { - super(then, isNew); + public ThenBreakModel(ProtocolType protocolType, ThenBreak then, Boolean isNew) { + super(protocolType, then, isNew); breakType = then.getBreakType(); } @@ -38,6 +39,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return breakType.getName(); + } + @Override public RuleOperationModelType getType() { return ThenModelType.Break; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java index 3f63b43..aac4986 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenBuildHttpMessageModel.java @@ -2,9 +2,10 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.rules.thens.ThenBuildHttpMessage; import synfron.reshaper.burp.core.rules.thens.entities.buildhttpmessage.MessageValueSetter; import synfron.reshaper.burp.core.vars.VariableSource; @@ -20,7 +21,7 @@ public class ThenBuildHttpMessageModel extends ThenModel implements IVariableCreator { @Getter - private DataDirection dataDirection; + private HttpDataDirection dataDirection; @Getter private String starterHttpMessage; @Getter @@ -32,8 +33,8 @@ public class ThenBuildHttpMessageModel extends ThenModel messageValueSetterChangedListener = this::onMessageValueSetterChanged; - public ThenBuildHttpMessageModel(ThenBuildHttpMessage then, Boolean isNew) { - super(then, isNew); + public ThenBuildHttpMessageModel(ProtocolType protocolType, ThenBuildHttpMessage then, Boolean isNew) { + super(protocolType, then, isNew); this.dataDirection = then.getDataDirection(); this.starterHttpMessage = VariableString.toString(then.getStarterHttpMessage(), starterHttpMessage); this.messageValueSetters = then.getMessageValueSetters().stream() @@ -59,7 +60,7 @@ public int removeMessageValueSetter(MessageValueSetterModel messageValueSetterMo return index; } - public void setDataDirection(DataDirection dataDirection) { + public void setDataDirection(HttpDataDirection dataDirection) { this.dataDirection = dataDirection; propertyChanged("dataDirection", dataDirection); } @@ -123,6 +124,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return dataDirection.name(); + } + @Override public RuleOperationModelType getType() { return ThenModelType.BuildHttpMessage; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenCommentModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenCommentModel.java index fa5ed03..974f2f0 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenCommentModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenCommentModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenComment; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -11,10 +12,10 @@ public class ThenCommentModel extends ThenModel { @Getter - private String text; + private String text = ""; - public ThenCommentModel(ThenComment then, Boolean isNew) { - super(then, isNew); + public ThenCommentModel(ProtocolType protocolType, ThenComment then, Boolean isNew) { + super(protocolType, then, isNew); text = VariableString.toString(then.getText(), text); } @@ -49,6 +50,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return abbreviateTargetName(text); + } + @Override public RuleOperationModelType getType() { return ThenModelType.Comment; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDelayModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDelayModel.java index bf9f2bc..e73ccf9 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDelayModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDelayModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenDelay; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -13,8 +14,8 @@ public class ThenDelayModel extends ThenModel { @Getter private String delay; - public ThenDelayModel(ThenDelay then, Boolean isNew) { - super(then, isNew); + public ThenDelayModel(ProtocolType protocolType, ThenDelay then, Boolean isNew) { + super(protocolType, then, isNew); delay = VariableString.toString(then.getDelay(), delay); } @@ -51,6 +52,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return delay; + } + @Override public RuleOperationModelType getType() { return ThenModelType.Delay; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteValueModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteValueModel.java index 65e2b75..d72b8b9 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteValueModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteValueModel.java @@ -2,12 +2,14 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.rules.thens.ThenDeleteValue; import synfron.reshaper.burp.core.utils.DeleteItemPlacement; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; +import java.util.Arrays; import java.util.List; public class ThenDeleteValueModel extends ThenModel { @@ -19,9 +21,9 @@ public class ThenDeleteValueModel extends ThenModel value.isDeletable(protocolType)).findFirst().orElse(null); identifier = VariableString.toString(then.getIdentifier(), identifier); identifierPlacement = then.getIdentifierPlacement(); } @@ -69,6 +71,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return messageValue.getName(); + } + @Override public RuleOperationModelType getType() { return ThenModelType.DeleteValue; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteVariableModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteVariableModel.java index fe30bac..03cb7b8 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteVariableModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDeleteVariableModel.java @@ -2,8 +2,10 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenDeleteVariable; import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -16,8 +18,8 @@ public class ThenDeleteVariableModel extends ThenModel getType() { return ThenModelType.DeleteVariable; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDropModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDropModel.java index 69ba9fc..16555a1 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDropModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenDropModel.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.models.rules.thens; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenDrop; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -9,8 +10,8 @@ public class ThenDropModel extends ThenModel { @Getter private boolean dropMessage; - public ThenDropModel(ThenDrop then, Boolean isNew) { - super(then, isNew); + public ThenDropModel(ProtocolType protocolType, ThenDrop then, Boolean isNew) { + super(protocolType, then, isNew); dropMessage = then.isDropMessage(); } @@ -37,6 +38,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return isDropMessage() ? "Yes" : "No"; + } + @Override public RuleOperationModelType getType() { return ThenModelType.Drop; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java index 36d2361..21eb35a 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenEvaluateModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenEvaluate; import synfron.reshaper.burp.core.rules.thens.entities.evaluate.Operation; import synfron.reshaper.burp.core.vars.VariableSource; @@ -25,8 +26,8 @@ public class ThenEvaluateModel extends ThenModel getType() { return ThenModelType.Evaluate; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenHighlightModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenHighlightModel.java index 6ff0fcc..4714376 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenHighlightModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenHighlightModel.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.models.rules.thens; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenHighlight; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -9,8 +10,8 @@ public class ThenHighlightModel extends ThenModel getType() { return ThenModelType.Highlight; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenInterceptModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenInterceptModel.java new file mode 100644 index 0000000..80d3ba8 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenInterceptModel.java @@ -0,0 +1,51 @@ +package synfron.reshaper.burp.ui.models.rules.thens; + +import lombok.Getter; +import synfron.reshaper.burp.core.InterceptResponse; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.rules.thens.ThenIntercept; +import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; + +public class ThenInterceptModel extends ThenModel { + + @Getter + private InterceptResponse interceptResponse; + + public ThenInterceptModel(ProtocolType protocolType, ThenIntercept then, Boolean isNew) { + super(protocolType, then, isNew); + interceptResponse = then.getInterceptResponse(); + } + + public void setInterceptResponse(InterceptResponse interceptResponse) { + this.interceptResponse = interceptResponse; + propertyChanged("interceptResponse", interceptResponse); + } + + public boolean persist() { + if (validate().size() != 0) { + return false; + } + ruleOperation.setInterceptResponse(interceptResponse); + setValidated(true); + return true; + } + + @Override + public boolean record() { + if (validate().size() != 0) { + return false; + } + setValidated(true); + return true; + } + + @Override + protected String getTargetName() { + return interceptResponse.getName(); + } + + @Override + public RuleOperationModelType getType() { + return ThenModelType.Intercept; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenLogModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenLogModel.java index 5a8f8c6..5d55d4e 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenLogModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenLogModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenLog; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -11,10 +12,10 @@ public class ThenLogModel extends ThenModel { @Getter - private String text; + private String text = ""; - public ThenLogModel(ThenLog then, Boolean isNew) { - super(then, isNew); + public ThenLogModel(ProtocolType protocolType, ThenLog then, Boolean isNew) { + super(protocolType, then, isNew); text = VariableString.toString(then.getText(), text); } @@ -49,6 +50,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return abbreviateTargetName(text); + } + @Override public RuleOperationModelType getType() { return ThenModelType.Log; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModel.java index 11de203..d50801c 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModel.java @@ -1,5 +1,6 @@ package synfron.reshaper.burp.ui.models.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.rules.thens.Then; @@ -9,8 +10,8 @@ public abstract class ThenModel

, T extends Then> extends RuleOperationModel { - public ThenModel(T ruleOperation, Boolean isNew) { - super(ruleOperation, isNew); + public ThenModel(ProtocolType protocolType, T ruleOperation, Boolean isNew) { + super(protocolType, ruleOperation, isNew); } public ThenModel withListener(IEventListener listener) { @@ -18,9 +19,10 @@ public ThenModel withListener(IEventListener listener) return this; } - public static ThenModel getNewModel(RuleOperationModelType ruleOperationProxyType) { + public static ThenModel getNewModel(ProtocolType protocolType, RuleOperationModelType ruleOperationProxyType) { return (ThenModel) ObjectUtils.construct( ruleOperationProxyType.getType(), + protocolType, ObjectUtils.construct( ruleOperationProxyType.getRuleOperationType().getType() ), @@ -28,12 +30,13 @@ public static ThenModel getNewModel(RuleOperationModelType ruleOperati ); } - public static ThenModel getModel(Then then) { + public static ThenModel getModel(ProtocolType protocolType, Then then) { return (ThenModel) ObjectUtils.construct( - ThenModelType.getTypes().stream() + ThenModelType.getTypes(ProtocolType.Any).stream() .filter(type -> type.getRuleOperationType() == then.getType()) .findFirst() .get().getType(), + protocolType, then, false ); diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java index 43c796e..931eabc 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenModelType.java @@ -1,41 +1,46 @@ package synfron.reshaper.burp.ui.models.rules.thens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.thens.*; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ThenModelType

, T extends Then> extends RuleOperationModelType { - public static final ThenModelType Break = new ThenModelType<>("Break", ThenBreakModel.class, ThenType.Break); - public static final ThenModelType Delay = new ThenModelType<>("Delay", ThenDelayModel.class, ThenType.Delay); - public static final ThenModelType Log = new ThenModelType<>("Log", ThenLogModel.class, ThenType.Log); - public static final ThenModelType Highlight = new ThenModelType<>("Highlight", ThenHighlightModel.class, ThenType.Highlight); - public static final ThenModelType Comment = new ThenModelType<>("Comment", ThenCommentModel.class, ThenType.Comment); - public static final ThenModelType Prompt = new ThenModelType<>("Prompt", ThenPromptModel.class, ThenType.Prompt); - public static final ThenModelType RunRules = new ThenModelType<>("Run Rules", ThenRunRulesModel.class, ThenType.RunRules); - public static final ThenModelType RunScript = new ThenModelType<>("Run Script", ThenRunScriptModel.class, ThenType.RunScript); - public static final ThenModelType Evaluate = new ThenModelType<>("Evaluate", ThenEvaluateModel.class, ThenType.Evaluate); - public static final ThenModelType SetEventDirection = new ThenModelType<>("Set Event Direction", ThenSetEventDirectionModel.class, ThenType.SetEventDirection); - public static final ThenModelType SetEncoding = new ThenModelType<>("Set Encoding", ThenSetEncodingModel.class, ThenType.SetEncoding); - public static final ThenModelType SetValue = new ThenModelType<>("Set Value", ThenSetValueModel.class, ThenType.SetValue); - public static final ThenModelType DeleteValue = new ThenModelType<>("Delete Value", ThenDeleteValueModel.class, ThenType.DeleteValue); - public static final ThenModelType SetVariable = new ThenModelType<>("Set Variable", ThenSetVariableModel.class, ThenType.SetVariable); - public static final ThenModelType DeleteVariable = new ThenModelType<>("Delete Variable", ThenDeleteVariableModel.class, ThenType.DeleteVariable); - public static final ThenModelType SaveFile = new ThenModelType<>("Save File", ThenSaveFileModel.class, ThenType.SaveFile); - public static final ThenModelType SendTo = new ThenModelType<>("Send To", ThenSendToModel.class, ThenType.SendTo); - public static final ThenModelType RunProcess = new ThenModelType<>("Run Process", ThenRunProcessModel.class, ThenType.RunProcess); - public static final ThenModelType BuildHttpMessage = new ThenModelType<>("Build HTTP Message", ThenBuildHttpMessageModel.class, ThenType.BuildHttpMessage); - public static final ThenModelType ParseHttpMessage = new ThenModelType<>("Parse HTTP Message", ThenParseHttpMessageModel.class, ThenType.ParseHttpMessage); - public static final ThenModelType SendRequest = new ThenModelType<>("Send Request", ThenSendRequestModel.class, ThenType.SendRequest); - public static final ThenModelType Drop = new ThenModelType<>("Drop", ThenDropModel.class, ThenType.Drop); + public static final ThenModelType Break = new ThenModelType<>(ThenBreakModel.class, ThenType.Break); + public static final ThenModelType Delay = new ThenModelType<>(ThenDelayModel.class, ThenType.Delay); + public static final ThenModelType Log = new ThenModelType<>(ThenLogModel.class, ThenType.Log); + public static final ThenModelType Highlight = new ThenModelType<>(ThenHighlightModel.class, ThenType.Highlight); + public static final ThenModelType Comment = new ThenModelType<>(ThenCommentModel.class, ThenType.Comment); + public static final ThenModelType Prompt = new ThenModelType<>(ThenPromptModel.class, ThenType.Prompt); + public static final ThenModelType RunRules = new ThenModelType<>(ThenRunRulesModel.class, ThenType.RunRules); + public static final ThenModelType RunScript = new ThenModelType<>(ThenRunScriptModel.class, ThenType.RunScript); + public static final ThenModelType Evaluate = new ThenModelType<>(ThenEvaluateModel.class, ThenType.Evaluate); + public static final ThenModelType SetEventDirection = new ThenModelType<>(ThenSetEventDirectionModel.class, ThenType.SetEventDirection); + public static final ThenModelType SetEncoding = new ThenModelType<>(ThenSetEncodingModel.class, ThenType.SetEncoding); + public static final ThenModelType SetValue = new ThenModelType<>(ThenSetValueModel.class, ThenType.SetValue); + public static final ThenModelType DeleteValue = new ThenModelType<>(ThenDeleteValueModel.class, ThenType.DeleteValue); + public static final ThenModelType SetVariable = new ThenModelType<>(ThenSetVariableModel.class, ThenType.SetVariable); + public static final ThenModelType DeleteVariable = new ThenModelType<>(ThenDeleteVariableModel.class, ThenType.DeleteVariable); + public static final ThenModelType SaveFile = new ThenModelType<>(ThenSaveFileModel.class, ThenType.SaveFile); + public static final ThenModelType SendTo = new ThenModelType<>(ThenSendToModel.class, ThenType.SendTo); + public static final ThenModelType RunProcess = new ThenModelType<>(ThenRunProcessModel.class, ThenType.RunProcess); + public static final ThenModelType BuildHttpMessage = new ThenModelType<>(ThenBuildHttpMessageModel.class, ThenType.BuildHttpMessage); + public static final ThenModelType ParseHttpMessage = new ThenModelType<>(ThenParseHttpMessageModel.class, ThenType.ParseHttpMessage); + public static final ThenModelType SendRequest = new ThenModelType<>(ThenSendRequestModel.class, ThenType.SendRequest); + public static final ThenModelType SendMessage = new ThenModelType<>(ThenSendMessageModel.class, ThenType.SendMessage); + public static final ThenModelType Drop = new ThenModelType<>(ThenDropModel.class, ThenType.Drop); + public static final ThenModelType Intercept = new ThenModelType<>(ThenInterceptModel.class, ThenType.Intercept); - private ThenModelType(String name, Class

type, RuleOperationType ruleOperationType) { - super(name, type, ruleOperationType); + private ThenModelType(Class

type, RuleOperationType ruleOperationType) { + super(type, ruleOperationType); } - public static List> getTypes() { - return List.of( + public static List> getTypes(ProtocolType protocolType) { + return Stream.of( Break, Delay, Log, @@ -57,7 +62,9 @@ public static List> getTypes() { BuildHttpMessage, ParseHttpMessage, SendRequest, - Drop - ); + SendMessage, + Drop, + Intercept + ).filter(type -> protocolType == null || type.hasProtocolType(protocolType)).collect(Collectors.toList()); } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java index 40dc89e..a58d7dd 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenParseHttpMessageModel.java @@ -2,9 +2,10 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.rules.thens.ThenParseHttpMessage; import synfron.reshaper.burp.core.rules.thens.entities.parsehttpmessage.MessageValueGetter; import synfron.reshaper.burp.core.vars.VariableSourceEntry; @@ -18,7 +19,7 @@ public class ThenParseHttpMessageModel extends ThenModel implements IVariableCreator { @Getter - private DataDirection dataDirection; + private HttpDataDirection dataDirection; @Getter private String httpMessage; @Getter @@ -26,8 +27,8 @@ public class ThenParseHttpMessageModel extends ThenModel messageValueGetterChangedListener = this::onMessageValueGetterChanged; - public ThenParseHttpMessageModel(ThenParseHttpMessage then, Boolean isNew) { - super(then, isNew); + public ThenParseHttpMessageModel(ProtocolType protocolType, ThenParseHttpMessage then, Boolean isNew) { + super(protocolType, then, isNew); this.dataDirection = then.getDataDirection(); this.httpMessage = VariableString.toString(then.getHttpMessage(), httpMessage); this.messageValueGetters = then.getMessageValueGetters().stream() @@ -51,7 +52,7 @@ public int removeMessageValueGetter(MessageValueGetterModel messageValueGetterMo return index; } - public void setDataDirection(DataDirection dataDirection) { + public void setDataDirection(HttpDataDirection dataDirection) { this.dataDirection = dataDirection; propertyChanged("dataDirection", dataDirection); } @@ -98,6 +99,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return dataDirection.name(); + } + @Override public RuleOperationModelType getType() { return ThenModelType.ParseHttpMessage; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java index c7b1282..a88ccb1 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenPromptModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenPrompt; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.core.vars.VariableSourceEntry; @@ -26,8 +27,8 @@ public class ThenPromptModel extends ThenModel impl @Getter private String captureVariableName; - public ThenPromptModel(ThenPrompt then, Boolean isNew) { - super(then, isNew); + public ThenPromptModel(ProtocolType protocolType, ThenPrompt then, Boolean isNew) { + super(protocolType, then, isNew); description = VariableString.toString(then.getDescription(), description); starterText = VariableString.toString(then.getStarterText(), starterText); failAfter = VariableString.toString(then.getFailAfter(), failAfter); @@ -108,6 +109,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return abbreviateTargetName(description); + } + @Override public RuleOperationModelType getType() { return ThenModelType.Prompt; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java index b8c4179..f5b5fac 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunProcessModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenRunProcess; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.core.vars.VariableSourceEntry; @@ -36,8 +37,8 @@ public class ThenRunProcessModel extends ThenModel getType() { return ThenModelType.RunProcess; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunRulesModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunRulesModel.java index 28e1b21..e2cf469 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunRulesModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunRulesModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenRunRules; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -14,8 +15,8 @@ public class ThenRunRulesModel extends ThenModel getType() { return ThenModelType.RunRules; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunScriptModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunScriptModel.java index aed7fa5..43d03e4 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunScriptModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenRunScriptModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenRunScript; import synfron.reshaper.burp.core.utils.TextUtils; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -15,8 +16,8 @@ public class ThenRunScriptModel extends ThenModel getType() { return ThenModelType.RunScript; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSaveFileModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSaveFileModel.java index 5ab7aac..505c09d 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSaveFileModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSaveFileModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.rules.thens.ThenSaveFile; import synfron.reshaper.burp.core.rules.thens.entities.savefile.FileExistsAction; @@ -21,8 +22,8 @@ public class ThenSaveFileModel extends ThenModel getType() { return ThenModelType.SaveFile; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendMessageModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendMessageModel.java new file mode 100644 index 0000000..a37fb2a --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendMessageModel.java @@ -0,0 +1,62 @@ +package synfron.reshaper.burp.ui.models.rules.thens; + +import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.WebSocketDataDirection; +import synfron.reshaper.burp.core.rules.thens.ThenSendMessage; +import synfron.reshaper.burp.core.vars.VariableString; +import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; + +public class ThenSendMessageModel extends ThenModel { + + @Getter + private WebSocketDataDirection dataDirection; + + @Getter + private String message = ""; + + public ThenSendMessageModel(ProtocolType protocolType, ThenSendMessage then, Boolean isNew) { + super(protocolType, then, isNew); + dataDirection = then.getDataDirection(); + message = VariableString.toString(then.getMessage(), message); + } + + public void setDataDirection(WebSocketDataDirection dataDirection) { + this.dataDirection = dataDirection; + propertyChanged("dataDirection", dataDirection); + } + + public void setMessage(String message) { + this.message = message; + propertyChanged("message", message); + } + + public boolean persist() { + if (validate().size() != 0) { + return false; + } + ruleOperation.setDataDirection(dataDirection); + ruleOperation.setMessage(VariableString.getAsVariableString(message)); + setValidated(true); + return true; + } + + @Override + public boolean record() { + if (validate().size() != 0) { + return false; + } + setValidated(true); + return true; + } + + @Override + protected String getTargetName() { + return abbreviateTargetName(message); + } + + @Override + public RuleOperationModelType getType() { + return ThenModelType.SendMessage; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java index 00a76d7..07a9dff 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSendRequestModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenSendRequest; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.core.vars.VariableSourceEntry; @@ -40,8 +41,8 @@ public class ThenSendRequestModel extends ThenModel { @Getter private String url; - public ThenSendToModel(ThenSendTo then, Boolean isNew) { - super(then, isNew); + public ThenSendToModel(ProtocolType protocolType, ThenSendTo then, Boolean isNew) { + super(protocolType, then, isNew); sendTo = then.getSendTo(); overrideDefaults = then.isOverrideDefaults(); host = VariableString.toString(then.getHost(), host); @@ -129,6 +130,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return sendTo.name(); + } + @Override public RuleOperationModelType getType() { return ThenModelType.SendTo; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEncodingModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEncodingModel.java index 4a8ce47..b5b16b6 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEncodingModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEncodingModel.java @@ -1,8 +1,7 @@ package synfron.reshaper.burp.ui.models.rules.thens; import lombok.Getter; -import org.apache.commons.lang3.StringUtils; -import org.apache.http.util.CharsetUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.Encoder; import synfron.reshaper.burp.core.rules.thens.ThenSetEncoding; import synfron.reshaper.burp.core.vars.VariableString; @@ -15,8 +14,8 @@ public class ThenSetEncodingModel extends ThenModel getType() { return ThenModelType.SetEncoding; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEventDirectionModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEventDirectionModel.java index 37c6d70..cfb3eca 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEventDirectionModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetEventDirectionModel.java @@ -1,21 +1,22 @@ package synfron.reshaper.burp.ui.models.rules.thens; import lombok.Getter; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.rules.thens.ThenSetEventDirection; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; public class ThenSetEventDirectionModel extends ThenModel { @Getter - private DataDirection dataDirection; + private HttpDataDirection dataDirection; - public ThenSetEventDirectionModel(ThenSetEventDirection then, Boolean isNew) { - super(then, isNew); + public ThenSetEventDirectionModel(ProtocolType protocolType, ThenSetEventDirection then, Boolean isNew) { + super(protocolType, then, isNew); dataDirection = then.getDataDirection(); } - public void setDataDirection(DataDirection dataDirection) { + public void setDataDirection(HttpDataDirection dataDirection) { this.dataDirection = dataDirection; propertyChanged("dataDirection", dataDirection); } @@ -38,6 +39,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return dataDirection.name(); + } + @Override public RuleOperationModelType getType() { return ThenModelType.SetEventDirection; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetModel.java index bb1878b..39c14b1 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetModel.java @@ -2,12 +2,14 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.messages.MessageValueType; import synfron.reshaper.burp.core.rules.thens.ThenSet; import synfron.reshaper.burp.core.utils.GetItemPlacement; import synfron.reshaper.burp.core.vars.VariableString; +import java.util.Arrays; import java.util.List; public abstract class ThenSetModel

, T extends ThenSet> extends ThenModel { @@ -37,10 +39,10 @@ public abstract class ThenSetModel

, T extends ThenS @Getter protected String destinationMessageValuePath = ""; - public ThenSetModel(T then, Boolean isNew) { - super(then, isNew); + public ThenSetModel(ProtocolType protocolType, T then, Boolean isNew) { + super(protocolType, then, isNew); useMessageValue = then.isUseMessageValue(); - sourceMessageValue = then.getSourceMessageValue(); + sourceMessageValue = then.getSourceMessageValue() != null ? then.getSourceMessageValue() : Arrays.stream(MessageValue.values()).filter(value -> value.isGettable(protocolType)).findFirst().orElse(null);; sourceIdentifier = VariableString.toString(then.getSourceIdentifier(), sourceIdentifier); sourceIdentifierPlacement = then.getSourceIdentifierPlacement(); sourceMessageValueType = then.getSourceMessageValueType(); diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetValueModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetValueModel.java index 576718a..81d3763 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetValueModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetValueModel.java @@ -2,12 +2,14 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.rules.thens.ThenSetValue; import synfron.reshaper.burp.core.utils.SetItemPlacement; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; +import java.util.Arrays; import java.util.List; public class ThenSetValueModel extends ThenSetModel { @@ -19,9 +21,9 @@ public class ThenSetValueModel extends ThenSetModel value.isSettable(protocolType)).findFirst().orElse(null);; destinationIdentifier = VariableString.toString(then.getDestinationIdentifier(), destinationIdentifier); destinationIdentifierPlacement = then.getDestinationIdentifierPlacement(); } @@ -70,6 +72,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return destinationMessageValue.getName(); + } + @Override public RuleOperationModelType getType() { return ThenModelType.SetValue; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java index 189cbdb..46858a3 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/thens/ThenSetVariableModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.thens.ThenSetVariable; import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.core.vars.VariableSourceEntry; @@ -18,8 +19,8 @@ public class ThenSetVariableModel extends ThenSetModel getType() { return ThenModelType.SetVariable; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenContentTypeModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenContentTypeModel.java index b71fe81..be1e57e 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenContentTypeModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenContentTypeModel.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.models.rules.whens; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.ContentType; import synfron.reshaper.burp.core.rules.whens.WhenContentType; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -10,8 +11,8 @@ public class WhenContentTypeModel extends WhenModel getType() { return WhenModelType.ContentType; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenEventDirectionModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenEventDirectionModel.java index db05060..447e3a2 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenEventDirectionModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenEventDirectionModel.java @@ -1,21 +1,22 @@ package synfron.reshaper.burp.ui.models.rules.whens; import lombok.Getter; -import synfron.reshaper.burp.core.messages.DataDirection; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.HttpDataDirection; import synfron.reshaper.burp.core.rules.whens.WhenEventDirection; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; public class WhenEventDirectionModel extends WhenModel { @Getter - private DataDirection dataDirection; + private HttpDataDirection dataDirection; - public WhenEventDirectionModel(WhenEventDirection when, Boolean isNew) { - super(when, isNew); + public WhenEventDirectionModel(ProtocolType protocolType, WhenEventDirection when, Boolean isNew) { + super(protocolType, when, isNew); dataDirection = when.getDataDirection(); } - public void setDataDirection(DataDirection dataDirection) { + public void setDataDirection(HttpDataDirection dataDirection) { this.dataDirection = dataDirection; propertyChanged("dataDirection", dataDirection); } @@ -37,6 +38,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return dataDirection.name(); + } + @Override public RuleOperationModelType getType() { return WhenModelType.EventDirection; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenFromToolModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenFromToolModel.java index 6908058..55e1a4d 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenFromToolModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenFromToolModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import synfron.reshaper.burp.core.BurpTool; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.whens.WhenFromTool; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -10,8 +11,8 @@ public class WhenFromToolModel extends WhenModel getType() { return WhenModelType.FromTool; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenHasEntityModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenHasEntityModel.java index 9030cce..f26f69f 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenHasEntityModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenHasEntityModel.java @@ -2,11 +2,13 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.rules.whens.WhenHasEntity; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; +import java.util.Arrays; import java.util.List; public class WhenHasEntityModel extends WhenModel { @@ -16,9 +18,9 @@ public class WhenHasEntityModel extends WhenModel value.isGettable(protocolType)).findFirst().orElse(null); identifier = VariableString.toString(when.getIdentifier(), identifier); } @@ -59,6 +61,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return messageValue.getName(); + } + @Override public RuleOperationModelType getType() { return WhenModelType.HasEntity; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenInScopeModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenInScopeModel.java index 01e45aa..f5ffeaa 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenInScopeModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenInScopeModel.java @@ -1,7 +1,7 @@ package synfron.reshaper.burp.ui.models.rules.whens; import lombok.Getter; -import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.whens.WhenInScope; import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -13,8 +13,8 @@ public class WhenInScopeModel extends WhenModel { @Getter private String url; - public WhenInScopeModel(WhenInScope when, Boolean isNew) { - super(when, isNew); + public WhenInScopeModel(ProtocolType protocolType, WhenInScope when, Boolean isNew) { + super(protocolType, when, isNew); url = VariableString.toString(when.getUrl(), url); } @@ -44,6 +44,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return abbreviateTargetName(url); + } + @Override public RuleOperationModelType getType() { return WhenModelType.InScope; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMatchesTextModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMatchesTextModel.java index e84b7ab..c884fc9 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMatchesTextModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMatchesTextModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.messages.MessageValueType; import synfron.reshaper.burp.core.rules.MatchType; @@ -10,6 +11,7 @@ import synfron.reshaper.burp.core.vars.VariableString; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; +import java.util.Arrays; import java.util.List; public class WhenMatchesTextModel extends WhenModel { @@ -19,6 +21,8 @@ public class WhenMatchesTextModel extends WhenModel value.isGettable(protocolType)).findFirst().orElse(null); identifier = VariableString.toString(when.getIdentifier(), identifier); identifierPlacement = when.getIdentifierPlacement(); messageValueType = when.getMessageValueType(); @@ -66,6 +71,11 @@ public void setMatchText(String matchText) { propertyChanged("matchText", matchText); } + public void setIgnoreCase(boolean ignoreCase) { + this.ignoreCase = ignoreCase; + propertyChanged("ignoreCase", ignoreCase); + } + public void setMessageValue(MessageValue messageValue) { this.messageValue = messageValue; propertyChanged("messageValue", messageValue); @@ -108,6 +118,7 @@ public boolean persist() { ruleOperation.setIdentifierPlacement(identifierPlacement); ruleOperation.setSourceText(VariableString.getAsVariableString(sourceText)); ruleOperation.setMatchText(VariableString.getAsVariableString(matchText)); + ruleOperation.setIgnoreCase(ignoreCase); ruleOperation.setMessageValue(messageValue); ruleOperation.setMessageValueType(messageValueType); ruleOperation.setMessageValuePath(VariableString.getAsVariableString(messageValuePath)); @@ -125,6 +136,11 @@ public boolean record() { return true; } + @Override + protected String getTargetName() { + return abbreviateTargetName(matchText); + } + @Override public RuleOperationModelType getType() { return WhenModelType.MatchesText; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMessageTypeModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMessageTypeModel.java new file mode 100644 index 0000000..6c34be5 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMessageTypeModel.java @@ -0,0 +1,50 @@ +package synfron.reshaper.burp.ui.models.rules.whens; + +import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.WebSocketMessageType; +import synfron.reshaper.burp.core.rules.whens.WhenMessageType; +import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; + +public class WhenMessageTypeModel extends WhenModel { + + @Getter + private WebSocketMessageType messageType; + + public WhenMessageTypeModel(ProtocolType protocolType, WhenMessageType when, Boolean isNew) { + super(protocolType, when, isNew); + messageType = when.getMessageType(); + } + + public void setMessageType(WebSocketMessageType messageType) { + this.messageType = messageType; + propertyChanged("messageType", messageType); + } + + public boolean persist() { + if (validate().size() != 0) { + return false; + } + ruleOperation.setMessageType(messageType); + return super.persist(); + } + + @Override + public boolean record() { + if (validate().size() != 0) { + return false; + } + setValidated(true); + return true; + } + + @Override + protected String getTargetName() { + return messageType.name(); + } + + @Override + public RuleOperationModelType getType() { + return WhenModelType.MessageType; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMimeTypeModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMimeTypeModel.java index 40f2cef..ba658aa 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMimeTypeModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenMimeTypeModel.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.models.rules.whens; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.messages.MimeType; import synfron.reshaper.burp.core.rules.whens.WhenMimeType; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -10,8 +11,8 @@ public class WhenMimeTypeModel extends WhenModel getType() { return WhenModelType.MimeType; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModel.java index e37121e..cd6d05e 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModel.java @@ -1,6 +1,7 @@ package synfron.reshaper.burp.ui.models.rules.whens; import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.rules.whens.When; @@ -15,8 +16,8 @@ public abstract class WhenModel

, T extends When> ex @Getter private boolean useOrCondition; - public WhenModel(T ruleOperation, Boolean isNew) { - super(ruleOperation, isNew); + public WhenModel(ProtocolType protocolType, T ruleOperation, Boolean isNew) { + super(protocolType, ruleOperation, isNew); negate = ruleOperation.isNegate(); useOrCondition = ruleOperation.isUseOrCondition(); } @@ -45,9 +46,10 @@ public boolean persist() { return true; } - public static WhenModel getNewModel(RuleOperationModelType ruleOperationModelType) { + public static WhenModel getNewModel(ProtocolType protocolType, RuleOperationModelType ruleOperationModelType) { return (WhenModel) ObjectUtils.construct( ruleOperationModelType.getType(), + protocolType, ObjectUtils.construct( ruleOperationModelType.getRuleOperationType().getType() ), @@ -55,12 +57,13 @@ public boolean persist() { ); } - public static WhenModel getModel(When when) { + public static WhenModel getModel(ProtocolType protocolType, When when) { return (WhenModel) ObjectUtils.construct( - WhenModelType.getTypes().stream() + WhenModelType.getTypes(ProtocolType.Any).stream() .filter(type -> type.getRuleOperationType() == when.getType()) .findFirst() .get().getType(), + protocolType, when, false ); diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModelType.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModelType.java index 85847e1..acb0538 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModelType.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenModelType.java @@ -1,35 +1,42 @@ package synfron.reshaper.burp.ui.models.rules.whens; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.RuleOperationType; import synfron.reshaper.burp.core.rules.whens.*; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class WhenModelType

, T extends When> extends RuleOperationModelType { - public static final WhenModelType EventDirection = new WhenModelType<>("Event Direction", WhenEventDirectionModel.class, WhenType.EventDirection); - public static final WhenModelType HasEntity = new WhenModelType<>("Has Entity", WhenHasEntityModel.class, WhenType.HasEntity); - public static final WhenModelType MatchesText = new WhenModelType<>("Matches Text", WhenMatchesTextModel.class, WhenType.MatchesText); - public static final WhenModelType ContentType = new WhenModelType<>("Content Type", WhenContentTypeModel.class, WhenType.ContentType); - public static final WhenModelType MimeType = new WhenModelType<>("MIME Type", WhenMimeTypeModel.class, WhenType.MimeType); - public static final WhenModelType ProxyName = new WhenModelType<>("Proxy Name", WhenProxyNameModel.class, WhenType.ProxyName); - public static final WhenModelType FromTool = new WhenModelType<>("From Tool", WhenFromToolModel.class, WhenType.FromTool); - public static final WhenModelType InScope = new WhenModelType<>("In Scope", WhenInScopeModel.class, WhenType.InScope); + public static final WhenModelType EventDirection = new WhenModelType<>(WhenEventDirectionModel.class, WhenType.EventDirection); + public static final WhenModelType WebSocketEventDirection = new WhenModelType<>(WhenWebSocketEventDirectionModel.class, WhenType.WebSocketEventDirection); + public static final WhenModelType HasEntity = new WhenModelType<>(WhenHasEntityModel.class, WhenType.HasEntity); + public static final WhenModelType MatchesText = new WhenModelType<>(WhenMatchesTextModel.class, WhenType.MatchesText); + public static final WhenModelType ContentType = new WhenModelType<>(WhenContentTypeModel.class, WhenType.ContentType); + public static final WhenModelType MimeType = new WhenModelType<>(WhenMimeTypeModel.class, WhenType.MimeType); + public static final WhenModelType MessageType = new WhenModelType<>(WhenMessageTypeModel.class, WhenType.MessageType); + public static final WhenModelType ProxyName = new WhenModelType<>(WhenProxyNameModel.class, WhenType.ProxyName); + public static final WhenModelType FromTool = new WhenModelType<>(WhenFromToolModel.class, WhenType.FromTool); + public static final WhenModelType InScope = new WhenModelType<>(WhenInScopeModel.class, WhenType.InScope); - private WhenModelType(String name, Class

type, RuleOperationType ruleOperationType) { - super(name, type, ruleOperationType); + private WhenModelType(Class

type, RuleOperationType ruleOperationType) { + super(type, ruleOperationType); } - public static List> getTypes() { - return List.of( + public static List> getTypes(ProtocolType protocolType) { + return Stream.of( EventDirection, + WebSocketEventDirection, HasEntity, MatchesText, ContentType, MimeType, + MessageType, ProxyName, FromTool, InScope - ); + ).filter(type -> type.hasProtocolType(protocolType)).collect(Collectors.toList()); } } diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenProxyNameModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenProxyNameModel.java index ee92a36..179aac6 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenProxyNameModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenProxyNameModel.java @@ -2,6 +2,7 @@ import lombok.Getter; import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.ProtocolType; import synfron.reshaper.burp.core.rules.whens.WhenProxyName; import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; @@ -12,8 +13,8 @@ public class WhenProxyNameModel extends WhenModel getType() { return WhenModelType.ProxyName; diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenWebSocketEventDirectionModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenWebSocketEventDirectionModel.java new file mode 100644 index 0000000..35894e0 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/whens/WhenWebSocketEventDirectionModel.java @@ -0,0 +1,50 @@ +package synfron.reshaper.burp.ui.models.rules.whens; + +import lombok.Getter; +import synfron.reshaper.burp.core.ProtocolType; +import synfron.reshaper.burp.core.messages.WebSocketDataDirection; +import synfron.reshaper.burp.core.rules.whens.WhenWebSocketEventDirection; +import synfron.reshaper.burp.ui.models.rules.RuleOperationModelType; + +public class WhenWebSocketEventDirectionModel extends WhenModel { + + @Getter + private WebSocketDataDirection dataDirection; + + public WhenWebSocketEventDirectionModel(ProtocolType protocolType, WhenWebSocketEventDirection when, Boolean isNew) { + super(protocolType, when, isNew); + dataDirection = when.getDataDirection(); + } + + public void setDataDirection(WebSocketDataDirection dataDirection) { + this.dataDirection = dataDirection; + propertyChanged("dataDirection", dataDirection); + } + + public boolean persist() { + if (validate().size() != 0) { + return false; + } + ruleOperation.setDataDirection(dataDirection); + return super.persist(); + } + + @Override + public boolean record() { + if (validate().size() != 0) { + return false; + } + setValidated(true); + return true; + } + + @Override + protected String getTargetName() { + return dataDirection.name(); + } + + @Override + public RuleOperationModelType getType() { + return WhenModelType.WebSocketEventDirection; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/AnnotationVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/AnnotationVariableTagWizardModel.java new file mode 100644 index 0000000..d83be6e --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/AnnotationVariableTagWizardModel.java @@ -0,0 +1,50 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import lombok.Getter; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.messages.MessageAnnotation; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; + +import java.util.ArrayList; +import java.util.List; + +public class AnnotationVariableTagWizardModel implements IVariableTagWizardModel { + + @Getter + private MessageAnnotation messageAnnotation = MessageAnnotation.Comment; + + @Getter + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setMessageAnnotation(MessageAnnotation messageAnnotation) { + this.messageAnnotation = messageAnnotation; + propertyChanged("messageAnnotation", messageAnnotation); + } + + @Override + public List validate() { + List errors = new ArrayList<>(); + return errors; + } + + @Override + public VariableSource getVariableSource() { + return VariableSource.Annotation; + } + + @Override + public String getTag() { + return validate().isEmpty() ? + VariableSourceEntry.getShortTag( + VariableSource.Annotation, + messageAnnotation.name().toLowerCase() + ) : + null; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java index fc35fb8..d04e329 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/CookieJarVariableTagWizardModel.java @@ -1,7 +1,7 @@ package synfron.reshaper.burp.ui.models.rules.wizard.vars; import burp.BurpExtender; -import burp.ICookie; +import burp.api.montoya.http.message.cookies.Cookie; import lombok.Getter; import org.apache.commons.lang3.StringUtils; import synfron.reshaper.burp.core.events.IEventListener; @@ -11,13 +11,16 @@ import synfron.reshaper.burp.core.vars.VariableSource; import synfron.reshaper.burp.core.vars.VariableSourceEntry; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.stream.Collectors; public class CookieJarVariableTagWizardModel implements IVariableTagWizardModel { @Getter private final Select domains; + private final List cookies; @Getter private Select names; @Getter @@ -27,8 +30,9 @@ public class CookieJarVariableTagWizardModel implements IVariableTagWizardModel private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); public CookieJarVariableTagWizardModel() { - List domains = BurpExtender.getCallbacks().getCookieJarContents().stream() - .map(ICookie::getDomain) + this.cookies = BurpExtender.getApi() != null ? BurpExtender.getApi().http().cookieJar().cookies() : Collections.emptyList(); + List domains = this.cookies.stream() + .map(Cookie::domain) .filter(StringUtils::isNotEmpty) .distinct() .collect(Collectors.toList()); @@ -43,9 +47,9 @@ public CookieJarVariableTagWizardModel withListener(IEventListener names = BurpExtender.getCallbacks().getCookieJarContents().stream() - .filter(cookie -> cookie.getDomain().equals(this.domains.getSelectedOption())) - .map(ICookie::getName) + List names = this.cookies.stream() + .filter(cookie -> cookie.domain().equals(this.domains.getSelectedOption())) + .map(Cookie::name) .filter(StringUtils::isNotEmpty) .distinct() .collect(Collectors.toList()); @@ -55,9 +59,9 @@ private void resetNames() { } private void resetPaths() { - List paths = BurpExtender.getCallbacks().getCookieJarContents().stream() - .filter(cookie -> cookie.getDomain().equals(this.domains.getSelectedOption()) && cookie.getDomain().equals(this.names.getSelectedOption())) - .map(ICookie::getPath) + List paths = this.cookies.stream() + .filter(cookie -> cookie.domain().equals(this.domains.getSelectedOption()) && cookie.domain().equals(this.names.getSelectedOption())) + .map(Cookie::path) .filter(StringUtils::isNotEmpty) .distinct() .collect(Collectors.toList()); diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionVariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionVariableTagWizardModel.java new file mode 100644 index 0000000..1afead3 --- /dev/null +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/SessionVariableTagWizardModel.java @@ -0,0 +1,66 @@ +package synfron.reshaper.burp.ui.models.rules.wizard.vars; + +import lombok.Getter; +import org.apache.commons.lang3.StringUtils; +import synfron.reshaper.burp.core.events.PropertyChangedArgs; +import synfron.reshaper.burp.core.events.PropertyChangedEvent; +import synfron.reshaper.burp.core.vars.VariableSource; +import synfron.reshaper.burp.core.vars.VariableSourceEntry; +import synfron.reshaper.burp.core.vars.VariableString; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class SessionVariableTagWizardModel implements IVariableTagWizardModel { + + @Getter + private final List variableNames; + + @Getter + private String variableName; + + @Getter + private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); + + public SessionVariableTagWizardModel(List entries) { + variableNames = entries.stream() + .filter(entry -> entry.getVariableSource() == VariableSource.Session) + .map(VariableSourceEntry::getName) + .filter(VariableString::isValidVariableName) + .distinct() + .sorted(String::compareToIgnoreCase) + .collect(Collectors.toList()); + variableName = variableNames.stream().findFirst().orElse(null); + } + + private void propertyChanged(String name, Object value) { + propertyChangedEvent.invoke(new PropertyChangedArgs(this, name, value)); + } + + public void setVariableName(String variableName) { + this.variableName = variableName; + propertyChanged("variableName", variableName); + } + + @Override + public List validate() { + List errors = new ArrayList<>(); + if (StringUtils.isEmpty(variableName)) { + errors.add("Variable Name is required"); + } + return errors; + } + + @Override + public VariableSource getVariableSource() { + return VariableSource.Session; + } + + @Override + public String getTag() { + return validate().isEmpty() ? + VariableSourceEntry.getShortTag(VariableSource.Session, variableName) : + null; + } +} diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java index 73eafe5..ded65a6 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/vars/VariableTagWizardModel.java @@ -41,10 +41,12 @@ public VariableTagWizardModel() { tagModelMap = Map.of( VariableSource.Event, new EventVariableTagWizardModel(variableSourceEntries), VariableSource.Global, new GlobalVariableTagWizardModel(variableSourceEntries), + VariableSource.Session, new SessionVariableTagWizardModel(variableSourceEntries), VariableSource.Message, new MessageVariableTagWizardModel(), VariableSource.File, new FileVariableTagWizardModel(), VariableSource.Special, new SpecialVariableTagWizardModel(), - VariableSource.CookieJar, new CookieJarVariableTagWizardModel() + VariableSource.CookieJar, new CookieJarVariableTagWizardModel(), + VariableSource.Annotation, new AnnotationVariableTagWizardModel() ); tagModel = tagModelMap.get(variableSource); diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardItemModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardItemModel.java index 216e35a..5c31515 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardItemModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardItemModel.java @@ -5,8 +5,8 @@ import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; -import synfron.reshaper.burp.core.messages.DataDirection; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.HttpDataDirection; +import synfron.reshaper.burp.core.messages.HttpEventInfo; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.messages.MessageValueHandler; import synfron.reshaper.burp.core.utils.GetItemPlacement; @@ -22,7 +22,7 @@ public class WhenWizardItemModel { @Getter private MessageValue messageValue; @Getter - private final IEventInfo eventInfo; + private final HttpEventInfo eventInfo; @Getter private Select identifiers = new Select<>(Collections.emptyList(), null); @Getter @@ -35,7 +35,7 @@ public class WhenWizardItemModel { @Getter private final PropertyChangedEvent propertyChangedEvent = new PropertyChangedEvent(); - public WhenWizardItemModel(MessageValue messageValue, IEventInfo eventInfo) { + public WhenWizardItemModel(MessageValue messageValue, HttpEventInfo eventInfo) { this.eventInfo = eventInfo; setMessageValue(messageValue); } @@ -108,7 +108,7 @@ public void setDeleted(boolean deleted) { } public boolean requiresResponse() { - return messageValue.getDataDirection() == DataDirection.Response; + return messageValue.getDataDirection() == HttpDataDirection.Response; } public List validate() { diff --git a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java index c784863..37d800f 100644 --- a/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java +++ b/src/main/java/synfron/reshaper/burp/ui/models/rules/wizard/whens/WhenWizardModel.java @@ -7,8 +7,8 @@ import synfron.reshaper.burp.core.events.IEventListener; import synfron.reshaper.burp.core.events.PropertyChangedArgs; import synfron.reshaper.burp.core.events.PropertyChangedEvent; -import synfron.reshaper.burp.core.messages.DataDirection; -import synfron.reshaper.burp.core.messages.IEventInfo; +import synfron.reshaper.burp.core.messages.HttpDataDirection; +import synfron.reshaper.burp.core.messages.HttpEventInfo; import synfron.reshaper.burp.core.messages.MessageValue; import synfron.reshaper.burp.core.rules.MatchType; import synfron.reshaper.burp.core.rules.Rule; @@ -28,7 +28,7 @@ public class WhenWizardModel implements IPrompterModel { @Getter - private final IEventInfo eventInfo; + private final HttpEventInfo eventInfo; @Getter private String ruleName; @Getter @@ -44,7 +44,7 @@ public class WhenWizardModel implements IPrompterModel { @Setter @Getter private ModalPrompter modalPrompter; - public WhenWizardModel(IEventInfo eventInfo) { + public WhenWizardModel(HttpEventInfo eventInfo) { this.eventInfo = eventInfo; } @@ -134,13 +134,13 @@ public boolean createRule() { } } WhenEventDirection direction = new WhenEventDirection(); - direction.setDataDirection(requiresResponse ? DataDirection.Response : DataDirection.Request); + direction.setDataDirection(requiresResponse ? HttpDataDirection.Response : HttpDataDirection.Request); whens.addFirst(direction); rule.setName(ruleName); rule.setEnabled(false); rule.setAutoRun(true); rule.setWhens(whens.toArray(When[]::new)); - BurpExtender.getConnector().getRulesEngine().getRulesRegistry().addRule(rule); + BurpExtender.getHttpConnector().getRulesEngine().getRulesRegistry().addRule(rule); setInvalidated(false); return true; } diff --git a/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java b/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java index 7c7a867..ad08168 100644 --- a/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java +++ b/src/main/java/synfron/reshaper/burp/ui/utils/ContextMenuHandler.java @@ -1,8 +1,9 @@ package synfron.reshaper.burp.ui.utils; -import burp.IContextMenuFactory; -import burp.IContextMenuInvocation; -import synfron.reshaper.burp.core.messages.EventInfo; +import burp.api.montoya.http.message.HttpRequestResponse; +import burp.api.montoya.ui.contextmenu.ContextMenuEvent; +import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider; +import synfron.reshaper.burp.core.messages.HttpEventInfo; import synfron.reshaper.burp.core.utils.Log; import synfron.reshaper.burp.ui.components.rules.wizard.whens.WhenWizardOptionPane; import synfron.reshaper.burp.ui.models.rules.wizard.whens.WhenWizardModel; @@ -12,17 +13,18 @@ import java.util.Collections; import java.util.List; -public class ContextMenuHandler implements IContextMenuFactory { +public class ContextMenuHandler implements ContextMenuItemsProvider { @Override - public List createMenuItems(IContextMenuInvocation invocation) { + public List provideMenuItems(ContextMenuEvent event) { JMenuItem menuItem = new JMenuItem("Create Rule"); - menuItem.addActionListener(actionEvent -> onCreateRule(invocation, actionEvent)); - return invocation.getSelectedMessages().length == 1 ? Collections.singletonList(menuItem) : Collections.emptyList(); + menuItem.addActionListener(actionEvent -> onCreateRule(event.selectedRequestResponses(), actionEvent)); + return event.selectedRequestResponses().size() == 1 ? Collections.singletonList(menuItem) : Collections.emptyList(); } - private void onCreateRule(IContextMenuInvocation invocation, ActionEvent actionEvent) { - openWhenWizard(new WhenWizardModel(new EventInfo(null, null, invocation.getSelectedMessages()[0]))); + private void onCreateRule(List selectedItems, ActionEvent actionEvent) { + HttpRequestResponse httpRequestResponse = selectedItems.get(0); + openWhenWizard(new WhenWizardModel(new HttpEventInfo(null, null, httpRequestResponse.httpRequest(), httpRequestResponse.httpResponse(), httpRequestResponse.messageAnnotations()))); } private void openWhenWizard(WhenWizardModel model) {