├── .gitignore ├── pics ├── diff_view.png ├── test_cors.png ├── compare_view.png ├── complete_gui.png ├── renew_session.png ├── test_anonymous.png ├── remove_csrftoken.png ├── several_sessions.png ├── several_sessions_1.png ├── idempotent_operations.png ├── param_replace_location.png ├── auto_extract_session_id.png ├── param_replace_locations.png ├── auto_extract_session_id_1.png ├── param_auto_extract_location.png ├── param_fromto_extract_location.png ├── session_header_with_csrf_token.png ├── auto_extract_csrftoken_from_js_var.png ├── parameter_settings_session_cookie.png ├── auto_extract_and_insert_bearer_token.png └── autp_extract_and_insert_bearer_token.png ├── resources ├── delete.png ├── erase.png ├── filter.png ├── loader.gif ├── p7_logo.png ├── refresh.png ├── info_icon.png └── settings.png ├── src ├── com │ └── protect7 │ │ └── authanalyzer │ │ ├── gui │ │ ├── listener │ │ │ ├── NewSessionListener.java │ │ │ ├── CloneSessionListener.java │ │ │ ├── DeleteSessionListener.java │ │ │ └── RenameSessionListener.java │ │ ├── util │ │ │ ├── AuthAnalyzerMenu.java │ │ │ ├── PlaceholderTextField.java │ │ │ ├── PlaceholderTextArea.java │ │ │ ├── BypassCellRenderer.java │ │ │ ├── HintCheckBox.java │ │ │ ├── CustomRowSorter.java │ │ │ ├── SessionTabbedPane.java │ │ │ └── RequestTableModel.java │ │ ├── main │ │ │ ├── MainPanel.java │ │ │ └── RequestResponsePanel.java │ │ ├── dialog │ │ │ ├── InfoDialog.java │ │ │ ├── SettingsDialog.java │ │ │ ├── DataExportDialog.java │ │ │ ├── MatchAndReplaceDialog.java │ │ │ ├── TokenSettingsDialog.java │ │ │ └── RepeatRequestFilterDialog.java │ │ └── entity │ │ │ └── StatusPanel.java │ │ ├── entities │ │ ├── TokenPriority.java │ │ ├── Range.java │ │ ├── TokenLocation.java │ │ ├── MatchAndReplace.java │ │ ├── AutoExtractLocation.java │ │ ├── TokenRequest.java │ │ ├── FromToExtractLocation.java │ │ ├── AnalyzerRequestResponse.java │ │ ├── OriginalRequestResponse.java │ │ ├── TokenBuilder.java │ │ ├── Session.java │ │ └── Token.java │ │ ├── util │ │ ├── BypassConstants.java │ │ ├── Globals.java │ │ ├── Setting.java │ │ ├── DataStorageProvider.java │ │ ├── GenericHelper.java │ │ ├── CurrentConfig.java │ │ ├── DataExporter.java │ │ └── ExtractionHelper.java │ │ ├── filter │ │ ├── InScopeFilter.java │ │ ├── MethodFilter.java │ │ ├── StatusCodeFilter.java │ │ ├── PathFilter.java │ │ ├── OnlyProxyFilter.java │ │ ├── QueryFilter.java │ │ ├── FileTypeFilter.java │ │ └── RequestFilter.java │ │ └── controller │ │ ├── HttpListener.java │ │ └── RequestController.java └── burp │ └── BurpExtender.java ├── BappManifest.bmf ├── LICENCE ├── BappDescription.html ├── pom.xml └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | backlog.txt 3 | debug.log 4 | .settings/ 5 | .project 6 | .classpath -------------------------------------------------------------------------------- /pics/diff_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/diff_view.png -------------------------------------------------------------------------------- /pics/test_cors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/test_cors.png -------------------------------------------------------------------------------- /pics/compare_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/compare_view.png -------------------------------------------------------------------------------- /pics/complete_gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/complete_gui.png -------------------------------------------------------------------------------- /resources/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/resources/delete.png -------------------------------------------------------------------------------- /resources/erase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/resources/erase.png -------------------------------------------------------------------------------- /resources/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/resources/filter.png -------------------------------------------------------------------------------- /resources/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/resources/loader.gif -------------------------------------------------------------------------------- /resources/p7_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/resources/p7_logo.png -------------------------------------------------------------------------------- /resources/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/resources/refresh.png -------------------------------------------------------------------------------- /pics/renew_session.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/renew_session.png -------------------------------------------------------------------------------- /pics/test_anonymous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/test_anonymous.png -------------------------------------------------------------------------------- /resources/info_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/resources/info_icon.png -------------------------------------------------------------------------------- /resources/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/resources/settings.png -------------------------------------------------------------------------------- /pics/remove_csrftoken.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/remove_csrftoken.png -------------------------------------------------------------------------------- /pics/several_sessions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/several_sessions.png -------------------------------------------------------------------------------- /pics/several_sessions_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/several_sessions_1.png -------------------------------------------------------------------------------- /pics/idempotent_operations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/idempotent_operations.png -------------------------------------------------------------------------------- /pics/param_replace_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/param_replace_location.png -------------------------------------------------------------------------------- /pics/auto_extract_session_id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/auto_extract_session_id.png -------------------------------------------------------------------------------- /pics/param_replace_locations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/param_replace_locations.png -------------------------------------------------------------------------------- /pics/auto_extract_session_id_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/auto_extract_session_id_1.png -------------------------------------------------------------------------------- /pics/param_auto_extract_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/param_auto_extract_location.png -------------------------------------------------------------------------------- /pics/param_fromto_extract_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/param_fromto_extract_location.png -------------------------------------------------------------------------------- /pics/session_header_with_csrf_token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/session_header_with_csrf_token.png -------------------------------------------------------------------------------- /pics/auto_extract_csrftoken_from_js_var.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/auto_extract_csrftoken_from_js_var.png -------------------------------------------------------------------------------- /pics/parameter_settings_session_cookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/parameter_settings_session_cookie.png -------------------------------------------------------------------------------- /pics/auto_extract_and_insert_bearer_token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/auto_extract_and_insert_bearer_token.png -------------------------------------------------------------------------------- /pics/autp_extract_and_insert_bearer_token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PortSwigger/auth-analyzer/main/pics/autp_extract_and_insert_bearer_token.png -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/listener/NewSessionListener.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.listener; 2 | 3 | public interface NewSessionListener { 4 | 5 | public void newSession(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/listener/CloneSessionListener.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.listener; 2 | 3 | public interface CloneSessionListener { 4 | 5 | public void cloneSession(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/listener/DeleteSessionListener.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.listener; 2 | 3 | public interface DeleteSessionListener { 4 | 5 | public void deleteSession(String sessionTitle); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/listener/RenameSessionListener.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.listener; 2 | 3 | public interface RenameSessionListener { 4 | 5 | public void renameSession(String currentName); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/TokenPriority.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | public class TokenPriority { 4 | 5 | private int priority = 0; 6 | 7 | public int getPriority() { 8 | return priority; 9 | } 10 | 11 | public void setPriority(int priority) { 12 | this.priority = priority; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/Range.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | public class Range { 4 | 5 | private final int minimum; 6 | private final int maximum; 7 | 8 | public Range(int minimum, int maximum) { 9 | this.minimum = minimum; 10 | this.maximum = maximum; 11 | } 12 | 13 | public int getMinimum() { 14 | return minimum; 15 | } 16 | 17 | public int getMaximum() { 18 | return maximum; 19 | } 20 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/TokenLocation.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | public enum TokenLocation { 4 | 5 | PATH("Path"), COOKIE("Cookie"), URL("URL (GET Parameter)"), BODY("Body (URL-Encoded / Multipart)"), JSON("Body (JSON)"); 6 | 7 | private final String name; 8 | 9 | public String getName() { 10 | return this.name; 11 | } 12 | 13 | private TokenLocation(String name) { 14 | this.name = name; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/MatchAndReplace.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | public class MatchAndReplace { 4 | 5 | private final String match; 6 | private final String replace; 7 | 8 | public MatchAndReplace(String match, String replace) { 9 | this.match = match; 10 | this.replace = replace; 11 | } 12 | 13 | public String getMatch() { 14 | return match; 15 | } 16 | 17 | public String getReplace() { 18 | return replace; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/util/BypassConstants.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.util; 2 | 3 | public enum BypassConstants { 4 | 5 | SAME("SAME"), SIMILAR("SIMILAR"), DIFFERENT("DIFFERENT"), NA("N/A"); 6 | 7 | 8 | private final String name; 9 | 10 | public String getName() { 11 | return this.name; 12 | } 13 | 14 | private BypassConstants(String name) { 15 | this.name = name; 16 | } 17 | 18 | @Override 19 | public String toString() { 20 | return name; 21 | } 22 | } -------------------------------------------------------------------------------- /BappManifest.bmf: -------------------------------------------------------------------------------- 1 | Uuid: 7db49799266c4f85866f54d9eab82c89 2 | ExtensionType: 1 3 | Name: Auth Analyzer 4 | RepoName: auth-analyzer 5 | ScreenVersion: 1.1.14 6 | SerialVersion: 27 7 | MinPlatformVersion: 0 8 | ProOnly: False 9 | Author: Simon Reinhart 10 | ShortDescription: This Burp Extension helps you to find authorization bugs by repeating Proxy requests with self defined headers and tokens. 11 | EntryPoint: target/AuthAnalyzer-1.1.14-jar-with-dependencies.jar 12 | BuildCommand: mvn package 13 | SupportedProducts: Pro, Community 14 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/AutoExtractLocation.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | import java.util.EnumSet; 4 | 5 | public enum AutoExtractLocation { 6 | 7 | COOKIE("Cookie"), 8 | HTML("HTML Document"), 9 | JSON("JSON Object"); 10 | 11 | private final String name; 12 | 13 | public String getName() { 14 | return this.name; 15 | } 16 | 17 | private AutoExtractLocation(String name) { 18 | this.name = name; 19 | } 20 | 21 | public static EnumSet getDefaultSet() { 22 | return EnumSet.of(COOKIE, HTML, JSON); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/util/Globals.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.util; 2 | 3 | public class Globals { 4 | 5 | public static final String VERSION = "1.1.14"; 6 | public static final String EXTENSION_NAME = "Auth Analyzer"; 7 | public static final String URL_GITHUB_PARAMETER_HELP = "https://github.com/simioni87/auth_analyzer/blob/main/README.md#parameter-extraction"; 8 | public static final String URL_GITHUB_ISSUE = "https://github.com/simioni87/auth_analyzer/issues/new"; 9 | public static final String URL_GITHUB_README = "https://github.com/simioni87/auth_analyzer/blob/main/README.md"; 10 | public static final String INSERTION_POINT_IDENTIFIER = "$$"; 11 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/TokenRequest.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | import burp.IHttpService; 4 | 5 | public class TokenRequest { 6 | 7 | private final int id; 8 | private final byte[] request; 9 | private final IHttpService httpService; 10 | private final int priority; 11 | public TokenRequest(int id, byte[] request, IHttpService httpService, int priority) { 12 | this.id = id; 13 | this.request = request; 14 | this.httpService = httpService; 15 | this.priority = priority; 16 | } 17 | public byte[] getRequest() { 18 | return request; 19 | } 20 | public int getPriority() { 21 | return priority; 22 | } 23 | public IHttpService getHttpService() { 24 | return httpService; 25 | } 26 | public int getId() { 27 | return id; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/filter/InScopeFilter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.filter; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IRequestInfo; 5 | import burp.IResponseInfo; 6 | 7 | public class InScopeFilter extends RequestFilter { 8 | 9 | public InScopeFilter(int filterIndex, String description) { 10 | super(filterIndex, description); 11 | } 12 | 13 | @Override 14 | public boolean filterRequest(IBurpExtenderCallbacks callbacks, int toolFlag, IRequestInfo requestInfo, 15 | IResponseInfo responseInfo) { 16 | if (onOffButton.isSelected() && !callbacks.isInScope(requestInfo.getUrl())) { 17 | incrementFiltered(); 18 | return true; 19 | } 20 | return false; 21 | } 22 | 23 | @Override 24 | public boolean hasStringLiterals() { 25 | return false; 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/FromToExtractLocation.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | import java.util.EnumSet; 4 | 5 | public enum FromToExtractLocation { 6 | 7 | HEADER("Response Header"), 8 | BODY("Response Body"), 9 | ALL("All Responses (incl. Binary)"), 10 | HTML("HTML Document"), 11 | JSON("JSON Object"), 12 | XML("XML Document"), 13 | TEXT("Plain Text"), 14 | SCRIPT("Script"), 15 | CSS("CSS"); 16 | 17 | private final String name; 18 | 19 | public String getName() { 20 | return this.name; 21 | } 22 | 23 | private FromToExtractLocation(String name) { 24 | this.name = name; 25 | } 26 | 27 | public static EnumSet getDefaultSet() { 28 | return EnumSet.of(HEADER, BODY, HTML, JSON, XML, TEXT); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/filter/MethodFilter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.filter; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IRequestInfo; 5 | import burp.IResponseInfo; 6 | 7 | public class MethodFilter extends RequestFilter { 8 | 9 | public MethodFilter(int filterIndex, String description) { 10 | super(filterIndex, description); 11 | setFilterStringLiterals(new String[]{"OPTIONS"}); 12 | } 13 | 14 | @Override 15 | public boolean filterRequest(IBurpExtenderCallbacks callbacks, int toolFlag, IRequestInfo requestInfo, IResponseInfo responseInfo) { 16 | if(onOffButton.isSelected()) { 17 | String requestMethod = requestInfo.getMethod(); 18 | for(String method : stringLiterals) { 19 | if(requestMethod.toLowerCase().equals(method.toLowerCase()) && !method.trim().equals("")) { 20 | incrementFiltered(); 21 | return true; 22 | } 23 | } 24 | } 25 | return false; 26 | } 27 | 28 | @Override 29 | public boolean hasStringLiterals() { 30 | return true; 31 | } 32 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/filter/StatusCodeFilter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.filter; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IRequestInfo; 5 | import burp.IResponseInfo; 6 | 7 | public class StatusCodeFilter extends RequestFilter { 8 | 9 | public StatusCodeFilter(int filterIndex, String description) { 10 | super(filterIndex, description); 11 | setFilterStringLiterals(new String[]{"304"}); 12 | } 13 | 14 | @Override 15 | public boolean filterRequest(IBurpExtenderCallbacks callbacks, int toolFlag, IRequestInfo requestInfo, IResponseInfo responseInfo) { 16 | if (onOffButton.isSelected() && responseInfo != null) { 17 | String statusCode = String.valueOf(responseInfo.getStatusCode()); 18 | for (String stringLiteral : stringLiterals) { 19 | if (statusCode.equals(stringLiteral.toLowerCase()) && !stringLiteral.trim().equals("")) { 20 | incrementFiltered(); 21 | return true; 22 | } 23 | } 24 | } 25 | return false; 26 | } 27 | 28 | @Override 29 | public boolean hasStringLiterals() { 30 | return true; 31 | } 32 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/filter/PathFilter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.filter; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IRequestInfo; 5 | import burp.IResponseInfo; 6 | 7 | public class PathFilter extends RequestFilter { 8 | 9 | public PathFilter(int filterIndex, String description) { 10 | super(filterIndex, description); 11 | setFilterStringLiterals(new String[]{}); 12 | } 13 | 14 | @Override 15 | public boolean filterRequest(IBurpExtenderCallbacks callbacks, int toolFlag, IRequestInfo requestInfo, IResponseInfo responseInfo) { 16 | if(onOffButton.isSelected() && requestInfo.getUrl().getPath() != null) { 17 | String url = requestInfo.getUrl().getPath().toString().toLowerCase(); 18 | for(String stringLiteral : stringLiterals) { 19 | if(url.contains(stringLiteral.toLowerCase()) && !stringLiteral.trim().equals("")) { 20 | incrementFiltered(); 21 | return true; 22 | } 23 | } 24 | } 25 | return false; 26 | } 27 | 28 | @Override 29 | public boolean hasStringLiterals() { 30 | return true; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Simon Reinhart 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/filter/OnlyProxyFilter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.filter; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IRequestInfo; 5 | import burp.IResponseInfo; 6 | 7 | public class OnlyProxyFilter extends RequestFilter { 8 | 9 | public OnlyProxyFilter(int filterIndex, String description) { 10 | super(filterIndex, description); 11 | } 12 | 13 | @Override 14 | public boolean filterRequest(IBurpExtenderCallbacks callbacks, int toolFlag, IRequestInfo requestInfo, IResponseInfo responseInfo) { 15 | if(onOffButton.isSelected()) { 16 | if(toolFlag == IBurpExtenderCallbacks.TOOL_PROXY) { 17 | return false; 18 | } 19 | else if(toolFlag == IBurpExtenderCallbacks.TOOL_REPEATER) { 20 | incrementFiltered(); 21 | } 22 | } 23 | else { 24 | //Only allow Repeater beside of Proxy 25 | if(toolFlag == IBurpExtenderCallbacks.TOOL_REPEATER || toolFlag == IBurpExtenderCallbacks.TOOL_PROXY) { 26 | return false; 27 | } 28 | } 29 | return true; 30 | } 31 | 32 | @Override 33 | public boolean hasStringLiterals() { 34 | return false; 35 | } 36 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/filter/QueryFilter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.filter; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IRequestInfo; 5 | import burp.IResponseInfo; 6 | 7 | public class QueryFilter extends RequestFilter { 8 | 9 | public QueryFilter(int filterIndex, String description) { 10 | super(filterIndex, description); 11 | setFilterStringLiterals(new String[]{}); 12 | } 13 | 14 | @Override 15 | public boolean filterRequest(IBurpExtenderCallbacks callbacks, int toolFlag, IRequestInfo requestInfo, IResponseInfo responseInfo) { 16 | if(onOffButton.isSelected()) { 17 | if(requestInfo.getUrl().getQuery() != null) { 18 | String query = requestInfo.getUrl().getQuery().toString().toLowerCase(); 19 | for(String stringLiteral : stringLiterals) { 20 | if(query.contains(stringLiteral.toLowerCase()) && !stringLiteral.trim().equals("")) { 21 | incrementFiltered(); 22 | return true; 23 | } 24 | } 25 | } 26 | } 27 | return false; 28 | } 29 | 30 | @Override 31 | public boolean hasStringLiterals() { 32 | return true; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/filter/FileTypeFilter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.filter; 2 | 3 | import burp.IBurpExtenderCallbacks; 4 | import burp.IRequestInfo; 5 | import burp.IResponseInfo; 6 | 7 | public class FileTypeFilter extends RequestFilter { 8 | 9 | 10 | public FileTypeFilter(int filterIndex, String description) { 11 | super(filterIndex, description); 12 | setFilterStringLiterals(new String[]{"js", "script", "css", "png", "jpg", "jpeg", "gif", "svg", "bmp", "woff", "ico"}); 13 | } 14 | 15 | @Override 16 | public boolean filterRequest(IBurpExtenderCallbacks callbacks, int toolFlag, IRequestInfo requestInfo, IResponseInfo responseInfo) { 17 | if(onOffButton.isSelected()) { 18 | String url = requestInfo.getUrl().getPath().toString().toLowerCase(); 19 | for(String fileType : stringLiterals) { 20 | if(url.endsWith(fileType.toLowerCase()) && !fileType.equals("")) { 21 | incrementFiltered(); 22 | return true; 23 | } 24 | else if(responseInfo != null && fileType.toLowerCase().equals(responseInfo.getInferredMimeType().toLowerCase())) { 25 | incrementFiltered(); 26 | return true; 27 | } 28 | } 29 | } 30 | return false; 31 | } 32 | 33 | @Override 34 | public boolean hasStringLiterals() { 35 | return true; 36 | } 37 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/util/AuthAnalyzerMenu.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.util; 2 | 3 | import javax.swing.JMenu; 4 | import javax.swing.JMenuItem; 5 | 6 | import com.protect7.authanalyzer.gui.dialog.InfoDialog; 7 | import com.protect7.authanalyzer.gui.dialog.SettingsDialog; 8 | 9 | import burp.BurpExtender; 10 | 11 | public class AuthAnalyzerMenu extends JMenu { 12 | 13 | private static final long serialVersionUID = 2230192165470056210L; 14 | 15 | public AuthAnalyzerMenu(String name) { 16 | super(name); 17 | JMenuItem exportSetupMenuItem = new JMenuItem("Export Setup"); 18 | exportSetupMenuItem.addActionListener(e -> BurpExtender.mainPanel.getConfigurationPanel().saveSetup()); 19 | add(exportSetupMenuItem); 20 | JMenuItem importSetupMenuItem = new JMenuItem("Import Setup"); 21 | importSetupMenuItem.addActionListener(e -> BurpExtender.mainPanel.getConfigurationPanel().loadSetup()); 22 | add(importSetupMenuItem); 23 | addSeparator(); 24 | JMenuItem settingsMenuItem = new JMenuItem("Settings"); 25 | settingsMenuItem.addActionListener(e -> new SettingsDialog(settingsMenuItem)); 26 | add(settingsMenuItem); 27 | addSeparator(); 28 | JMenuItem aboutMenuItem = new JMenuItem("About"); 29 | aboutMenuItem.addActionListener(e -> new InfoDialog(aboutMenuItem)); 30 | add(aboutMenuItem); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/util/PlaceholderTextField.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.util; 2 | 3 | import java.awt.Graphics; 4 | import java.awt.Graphics2D; 5 | import java.awt.RenderingHints; 6 | 7 | import javax.swing.JTextField; 8 | 9 | public class PlaceholderTextField extends JTextField { 10 | 11 | private static final long serialVersionUID = 5734794485649557381L; 12 | private String placeholder; 13 | 14 | public PlaceholderTextField() { 15 | super(); 16 | } 17 | 18 | public PlaceholderTextField(final int pColumns) { 19 | super(pColumns); 20 | } 21 | 22 | @Override 23 | protected void paintComponent(final Graphics pG) { 24 | super.paintComponent(pG); 25 | 26 | if (placeholder == null || placeholder.length() == 0 || getText().length() > 0) { 27 | return; 28 | } 29 | 30 | final Graphics2D g = (Graphics2D) pG; 31 | g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 32 | g.setColor(getDisabledTextColor()); 33 | g.drawString(placeholder, getInsets().left, pG.getFontMetrics().getMaxAscent() + getInsets().top); 34 | } 35 | 36 | public void setPlaceholder(String placeholder) { 37 | this.placeholder = placeholder; 38 | } 39 | 40 | public String getPlaceholder() { 41 | return placeholder; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/AnalyzerRequestResponse.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | /** 4 | * This Entity holds a HTTP Message created by the RequestController. (A repeated request with modified content) 5 | * 6 | * @author Simon Reinhart 7 | */ 8 | 9 | 10 | import com.protect7.authanalyzer.util.BypassConstants; 11 | 12 | import burp.IHttpRequestResponse; 13 | 14 | public class AnalyzerRequestResponse { 15 | 16 | private final IHttpRequestResponse requestResponse; 17 | private final BypassConstants status; 18 | private final String infoText; 19 | private final int statusCode; 20 | private final int responseContentLength; 21 | 22 | public AnalyzerRequestResponse(IHttpRequestResponse requestResponse, BypassConstants status, String infoText, 23 | int statusCode, int responseContentLength) { 24 | this.requestResponse = requestResponse; 25 | this.status = status; 26 | this.infoText = infoText; 27 | this.statusCode = statusCode; 28 | this.responseContentLength = responseContentLength; 29 | } 30 | 31 | public IHttpRequestResponse getRequestResponse() { 32 | return requestResponse; 33 | } 34 | 35 | public BypassConstants getStatus() { 36 | return status; 37 | } 38 | 39 | public String getInfoText() { 40 | return infoText; 41 | } 42 | 43 | public int getStatusCode() { 44 | return statusCode; 45 | } 46 | 47 | public int getResponseContentLength() { 48 | return responseContentLength; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /BappDescription.html: -------------------------------------------------------------------------------- 1 |

The Burp extension helps you to find authorization bugs. Just navigate through the web application with a high privileged user and let the Auth Analyzer repeat your requests for any defined non-privileged user. With the possibility to define Parameters the Auth Analyzer is able to extract and replace parameter values automatically. With this for instance, CSRF tokens or even whole session characteristics can be auto extracted from responses and replaced in further requests. Each response will be analyzed and tagged on its bypass status.

2 | 3 |

Authorization Tests can be performed in a semi automated way if you have the resources you want to test in your sitemap. In the very first step define your sessions you want to test. Then just expand your sitemap, select the resources and repeat the requests through the context menu. Additionally you can define some options which requests should be repeated and which not. With this you can perform authorization tests of a complex website within seconds.

4 | 5 |

Main Features

6 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/main/MainPanel.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.main; 2 | 3 | import java.awt.BorderLayout; 4 | import javax.swing.JPanel; 5 | import javax.swing.JScrollPane; 6 | import javax.swing.JSplitPane; 7 | import javax.swing.border.EmptyBorder; 8 | import com.protect7.authanalyzer.controller.ContextMenuController; 9 | 10 | import burp.BurpExtender; 11 | 12 | public class MainPanel extends JPanel { 13 | 14 | private static final long serialVersionUID = -8438576029794021570L; 15 | private final ConfigurationPanel configurationPanel; 16 | private final JSplitPane splitPane; 17 | private final CenterPanel centerPanel; 18 | 19 | public MainPanel() { 20 | setLayout(new BorderLayout(10, 10)); 21 | setBorder(new EmptyBorder(5, 5, 5, 5)); 22 | centerPanel = new CenterPanel(this); 23 | configurationPanel = new ConfigurationPanel(this); 24 | JScrollPane scrollPane = new JScrollPane(configurationPanel); 25 | scrollPane.getVerticalScrollBar().setUnitIncrement(20); 26 | splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, centerPanel); 27 | splitPane.setDividerSize(5); 28 | add(splitPane, BorderLayout.CENTER); 29 | BurpExtender.callbacks.registerContextMenuFactory(new ContextMenuController(configurationPanel)); 30 | configurationPanel.loadAutoStoredData(); 31 | } 32 | 33 | public void updateDividerLocation() { 34 | double configPanelHeight = configurationPanel.getPreferredSize().getHeight(); 35 | double currentSize = getSize().getHeight(); 36 | double relation = configPanelHeight/currentSize; 37 | if(relation > 0.0 && relation < 1.0) { 38 | splitPane.setDividerLocation(relation); 39 | } 40 | else { 41 | splitPane.setResizeWeight(0.2d); 42 | } 43 | } 44 | 45 | public CenterPanel getCenterPanel() { 46 | return centerPanel; 47 | } 48 | 49 | public ConfigurationPanel getConfigurationPanel() { 50 | return configurationPanel; 51 | } 52 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/util/PlaceholderTextArea.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.util; 2 | 3 | import java.awt.Color; 4 | import java.awt.Graphics; 5 | import java.awt.Graphics2D; 6 | import java.awt.RenderingHints; 7 | import javax.swing.BorderFactory; 8 | import javax.swing.JTextArea; 9 | import javax.swing.JToolTip; 10 | import javax.swing.border.Border; 11 | 12 | public class PlaceholderTextArea extends JTextArea { 13 | 14 | private static final long serialVersionUID = 5734794485649557381L; 15 | private String placeholder; 16 | 17 | public PlaceholderTextArea() { 18 | super(); 19 | init(); 20 | } 21 | 22 | public PlaceholderTextArea(int rows, int columns) { 23 | super(rows, columns); 24 | init(); 25 | } 26 | 27 | public JToolTip createToolTip() 28 | { 29 | JToolTip tip = new JToolTip(); 30 | tip.setComponent(this); 31 | tip.putClientProperty("html.disable", null); 32 | return tip; 33 | } 34 | 35 | private void init() { 36 | Border border = BorderFactory.createLineBorder(Color.LIGHT_GRAY); 37 | setBorder(BorderFactory.createCompoundBorder(border, BorderFactory.createEmptyBorder(2, 5, 2, 5))); 38 | setLineWrap(true); 39 | } 40 | 41 | @Override 42 | protected void paintComponent(final Graphics pG) { 43 | super.paintComponent(pG); 44 | 45 | if (placeholder == null || placeholder.length() == 0 || getText().length() > 0) { 46 | return; 47 | } 48 | 49 | final Graphics2D g = (Graphics2D) pG; 50 | g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 51 | g.setColor(getDisabledTextColor()); 52 | g.drawString(placeholder, getInsets().left, pG.getFontMetrics().getMaxAscent() + getInsets().top); 53 | } 54 | 55 | public void setPlaceholder(String placeholder) { 56 | this.placeholder = placeholder; 57 | } 58 | 59 | public String getPlaceholder() { 60 | return placeholder; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/dialog/InfoDialog.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.dialog; 2 | 3 | import java.awt.Component; 4 | import java.awt.Desktop; 5 | import java.awt.GridLayout; 6 | import java.awt.event.MouseAdapter; 7 | import java.awt.event.MouseEvent; 8 | import java.net.URI; 9 | import javax.swing.ImageIcon; 10 | import javax.swing.JButton; 11 | import javax.swing.JDialog; 12 | import javax.swing.JLabel; 13 | import javax.swing.JOptionPane; 14 | import javax.swing.JPanel; 15 | import javax.swing.JSeparator; 16 | import javax.swing.WindowConstants; 17 | import javax.swing.border.EmptyBorder; 18 | import com.protect7.authanalyzer.util.Globals; 19 | 20 | public class InfoDialog extends JDialog { 21 | 22 | private static final long serialVersionUID = -5052136850829972442L; 23 | 24 | public InfoDialog(Component parent) { 25 | setTitle(Globals.EXTENSION_NAME + " - About"); 26 | JPanel dialogPanel = (JPanel) getContentPane(); 27 | dialogPanel.setBorder(new EmptyBorder(10, 50, 30, 50)); 28 | dialogPanel.setLayout(new GridLayout(0, 1, 10, 10)); 29 | 30 | JLabel title = new JLabel("Auth Analyzer"); 31 | title.putClientProperty("html.disable", null); 32 | add(title); 33 | add(new JLabel("Version: " + Globals.VERSION)); 34 | add(new JLabel("Developed by: Simon Reinhart")); 35 | add(new JSeparator()); 36 | 37 | JButton helpButton = new JButton("Help"); 38 | helpButton.addActionListener(e -> openWebsite(Globals.URL_GITHUB_README)); 39 | add(helpButton); 40 | 41 | JButton issueButton = new JButton("Report an Issue"); 42 | issueButton.addActionListener(e -> openWebsite(Globals.URL_GITHUB_ISSUE)); 43 | add(issueButton); 44 | 45 | setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 46 | setVisible(true); 47 | pack(); 48 | setLocationRelativeTo(parent); 49 | } 50 | 51 | private void openWebsite(String url) { 52 | try { 53 | Desktop.getDesktop().browse(new URI(url)); 54 | } catch (Exception e1) { 55 | JOptionPane.showMessageDialog(this, "Browser can not be opened.", "Error", JOptionPane.WARNING_MESSAGE); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/util/BypassCellRenderer.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.util; 2 | 3 | import java.awt.Color; 4 | import java.awt.Component; 5 | 6 | import javax.swing.JTable; 7 | import javax.swing.table.DefaultTableCellRenderer; 8 | 9 | import com.protect7.authanalyzer.entities.OriginalRequestResponse; 10 | import com.protect7.authanalyzer.util.BypassConstants; 11 | 12 | public class BypassCellRenderer extends DefaultTableCellRenderer { 13 | 14 | private static final long serialVersionUID = 1L; 15 | 16 | 17 | @Override 18 | public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, 19 | int row, int column) { 20 | Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 21 | if (value instanceof BypassConstants && !value.toString().equals(BypassConstants.NA.toString())) { 22 | BypassConstants bypassConstant = (BypassConstants) value; 23 | if (bypassConstant == BypassConstants.SAME) { 24 | if (!isSelected) { 25 | c.setBackground(new Color(255, 51, 51, 80)); 26 | } 27 | } 28 | if (bypassConstant == BypassConstants.SIMILAR) { 29 | if (!isSelected) { 30 | c.setBackground(new Color(255, 153, 0, 80)); 31 | } 32 | } 33 | if (bypassConstant == BypassConstants.DIFFERENT) { 34 | if (!isSelected) { 35 | c.setBackground(new Color(0, 255, 51, 80)); 36 | } 37 | } 38 | } 39 | else { 40 | RequestTableModel tableModel = (RequestTableModel) table.getModel(); 41 | final OriginalRequestResponse requestResponse = tableModel.getOriginalRequestResponse(table.convertRowIndexToModel(row)); 42 | if(requestResponse.isMarked()) { 43 | if(!isSelected) { 44 | c.setBackground(new Color(255, 255, 0, 120)); 45 | } 46 | else { 47 | c.setBackground(new Color(210, 210, 0, 120)); 48 | } 49 | } 50 | else { 51 | if(!isSelected) { 52 | if(row % 2 == 0) { 53 | c.setBackground(table.getBackground()); 54 | } 55 | else { 56 | c.setBackground(new Color(200, 200, 200, 80)); 57 | } 58 | } 59 | } 60 | } 61 | return c; 62 | } 63 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/OriginalRequestResponse.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | import burp.IHttpRequestResponse; 4 | 5 | public class OriginalRequestResponse implements Comparable{ 6 | 7 | private final int id; 8 | private final IHttpRequestResponse requestResponse; 9 | private final String method; 10 | private final String host; 11 | private final String url; 12 | private final String infoText; 13 | private String comment = ""; 14 | private final int statusCode; 15 | private final int responseContentLength; 16 | private boolean marked = false; 17 | 18 | public OriginalRequestResponse(int id, IHttpRequestResponse requestResponse, String method, 19 | String url, String infoText, int statusCode, int responseContentLength) { 20 | this.id = id; 21 | this.requestResponse = requestResponse; 22 | this.method = method; 23 | this.host = requestResponse.getHttpService().getHost(); 24 | this.url = url; 25 | this.infoText = infoText; 26 | this.statusCode = statusCode; 27 | this.responseContentLength = responseContentLength; 28 | } 29 | public String getEndpoint() { 30 | return method + host + url; 31 | } 32 | public int getId() { 33 | return id; 34 | } 35 | public IHttpRequestResponse getRequestResponse() { 36 | return requestResponse; 37 | } 38 | public String getMethod() { 39 | return method; 40 | } 41 | public String getHost() { 42 | return host; 43 | } 44 | public String getUrl() { 45 | return url; 46 | } 47 | public boolean isMarked() { 48 | return marked; 49 | } 50 | public void setMarked(boolean marked) { 51 | this.marked = marked; 52 | } 53 | public String getInfoText() { 54 | return infoText; 55 | } 56 | @Override 57 | public int compareTo(OriginalRequestResponse o) { 58 | Integer id = this.getId(); 59 | return id.compareTo(o.getId()); 60 | } 61 | public int getStatusCode() { 62 | return statusCode; 63 | } 64 | public int getResponseContentLength() { 65 | return responseContentLength; 66 | } 67 | public void setComment(String comment) { 68 | this.comment = comment; 69 | } 70 | public String getComment() { 71 | return comment; 72 | } 73 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/controller/HttpListener.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.controller; 2 | 3 | import com.protect7.authanalyzer.filter.RequestFilter; 4 | import com.protect7.authanalyzer.util.CurrentConfig; 5 | import burp.BurpExtender; 6 | import burp.IBurpExtenderCallbacks; 7 | import burp.IHttpListener; 8 | import burp.IHttpRequestResponse; 9 | import burp.IInterceptedProxyMessage; 10 | import burp.IProxyListener; 11 | import burp.IRequestInfo; 12 | import burp.IResponseInfo; 13 | 14 | public class HttpListener implements IHttpListener, IProxyListener { 15 | 16 | private final CurrentConfig config = CurrentConfig.getCurrentConfig(); 17 | 18 | @Override 19 | public void processHttpMessage(int toolFlag, boolean messageIsRequest, IHttpRequestResponse messageInfo) { 20 | if(config.isRunning() && (!messageIsRequest || (messageIsRequest && config.isDropOriginal() && toolFlag == IBurpExtenderCallbacks.TOOL_PROXY))) { 21 | if(!isFiltered(toolFlag, messageInfo)) { 22 | config.performAuthAnalyzerRequest(messageInfo); 23 | } 24 | } 25 | } 26 | 27 | @Override 28 | public void processProxyMessage(boolean messageIsRequest, IInterceptedProxyMessage message) { 29 | if(config.isDropOriginal() && messageIsRequest) { 30 | if(!isFiltered(IBurpExtenderCallbacks.TOOL_PROXY, message.getMessageInfo())) { 31 | processHttpMessage(IBurpExtenderCallbacks.TOOL_PROXY, true, message.getMessageInfo()); 32 | message.setInterceptAction(IInterceptedProxyMessage.ACTION_DROP); 33 | } 34 | } 35 | } 36 | 37 | private boolean isFiltered(int toolFlag, IHttpRequestResponse messageInfo) { 38 | boolean isFiltered = false; 39 | IRequestInfo requestInfo = BurpExtender.callbacks.getHelpers().analyzeRequest(messageInfo); 40 | IResponseInfo responseInfo = null; 41 | if(messageInfo.getResponse() != null) { 42 | responseInfo = BurpExtender.callbacks.getHelpers().analyzeResponse(messageInfo.getResponse()); 43 | } 44 | for(int i=0; i 4 | 4.0.0 5 | com.protect7.authanalyzer 6 | AuthAnalyzer 7 | 1.1.14 8 | Burp Extension 9 | 10 | UTF-8 11 | 12 | 13 | src 14 | 15 | 16 | maven-compiler-plugin 17 | 3.8.0 18 | 19 | 1.8 20 | 1.8 21 | UTF-8 22 | 23 | 24 | 25 | maven-assembly-plugin 26 | 2.2 27 | 28 | 29 | jar-with-dependencies 30 | 31 | 32 | 33 | 34 | make-assembly 35 | package 36 | 37 | single 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | resources 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | com.google.code.gson 54 | gson 55 | 2.8.6 56 | 57 | 58 | 59 | 60 | org.jsoup 61 | jsoup 62 | 1.13.1 63 | 64 | 65 | 66 | net.portswigger.burp.extender 67 | burp-extender-api 68 | 2.3 69 | 70 | 71 | junit 72 | junit 73 | 4.11 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.awt.Component; 4 | import javax.swing.JFrame; 5 | import javax.swing.JMenu; 6 | import javax.swing.JMenuBar; 7 | import javax.swing.JTabbedPane; 8 | import javax.swing.SwingUtilities; 9 | import com.protect7.authanalyzer.controller.HttpListener; 10 | import com.protect7.authanalyzer.gui.main.MainPanel; 11 | import com.protect7.authanalyzer.gui.util.AuthAnalyzerMenu; 12 | import com.protect7.authanalyzer.util.DataStorageProvider; 13 | import com.protect7.authanalyzer.util.GenericHelper; 14 | import com.protect7.authanalyzer.util.Globals; 15 | 16 | public class BurpExtender implements IBurpExtender, ITab, IExtensionStateListener { 17 | 18 | public static MainPanel mainPanel; 19 | private JMenu authAnalyzerMenu = null; 20 | public static IBurpExtenderCallbacks callbacks; 21 | public static JTabbedPane burpTabbedPane = null; 22 | 23 | @Override 24 | public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks) { 25 | BurpExtender.callbacks = callbacks; 26 | callbacks.setExtensionName(Globals.EXTENSION_NAME); 27 | mainPanel = new MainPanel(); 28 | callbacks.addSuiteTab(this); 29 | addAuthAnalyzerMenu(); 30 | HttpListener httpListener = new HttpListener(); 31 | callbacks.registerHttpListener(httpListener); 32 | callbacks.registerProxyListener(httpListener); 33 | callbacks.registerExtensionStateListener(this); 34 | callbacks.printOutput(Globals.EXTENSION_NAME + " successfully started"); 35 | callbacks.printOutput("Version " + Globals.VERSION); 36 | callbacks.printOutput("Created by Simon Reinhart"); 37 | } 38 | 39 | @Override 40 | public String getTabCaption() { 41 | return Globals.EXTENSION_NAME; 42 | } 43 | 44 | @Override 45 | public Component getUiComponent() { 46 | return mainPanel; 47 | } 48 | 49 | private void addAuthAnalyzerMenu() { 50 | SwingUtilities.invokeLater(new Runnable() { 51 | 52 | @Override 53 | public void run() { 54 | JFrame burpFrame = GenericHelper.getBurpFrame(); 55 | if(burpFrame != null) { 56 | authAnalyzerMenu = new AuthAnalyzerMenu(Globals.EXTENSION_NAME); 57 | JMenuBar burpMenuBar = burpFrame.getJMenuBar(); 58 | burpMenuBar.add(authAnalyzerMenu, burpMenuBar.getMenuCount() - 1); 59 | } 60 | } 61 | }); 62 | 63 | } 64 | 65 | @Override 66 | public void extensionUnloaded() { 67 | if(authAnalyzerMenu != null && authAnalyzerMenu.getParent() != null) { 68 | authAnalyzerMenu.getParent().remove(authAnalyzerMenu); 69 | } 70 | try { 71 | mainPanel.getConfigurationPanel().createSessionObjects(false); 72 | DataStorageProvider.saveSetup(); 73 | } 74 | catch (Exception e) { 75 | callbacks.printOutput("INFO: Session Setup not stored due to invalid data."); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/filter/RequestFilter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.filter; 2 | 3 | import java.awt.Color; 4 | import com.protect7.authanalyzer.gui.util.HintCheckBox; 5 | import com.protect7.authanalyzer.util.GenericHelper; 6 | import burp.IBurpExtenderCallbacks; 7 | import burp.IRequestInfo; 8 | import burp.IResponseInfo; 9 | 10 | public abstract class RequestFilter { 11 | 12 | protected HintCheckBox onOffButton = null; 13 | protected int amountOfFilteredRequests = 0; 14 | protected String[] stringLiterals = null; 15 | private final int filterIndex; 16 | private final String description; 17 | 18 | public RequestFilter(int filterIndex, String description) { 19 | this.filterIndex = filterIndex; 20 | this.description = description; 21 | } 22 | 23 | public void registerOnOffButton(HintCheckBox button) { 24 | onOffButton = button; 25 | onOffButton.putClientProperty("html.disable", null); 26 | onOffButton.setHint(getInfoText()); 27 | } 28 | 29 | protected void incrementFiltered() { 30 | amountOfFilteredRequests++; 31 | if(onOffButton != null) { 32 | String textWihtoutFilterAmount = onOffButton.getText().split(" \\(")[0]; 33 | onOffButton.setText(textWihtoutFilterAmount + " (Filtered: " + amountOfFilteredRequests + ")"); 34 | GenericHelper.uiUpdateAnimation(onOffButton, new Color(240, 110, 0)); 35 | } 36 | } 37 | 38 | public void resetFilteredAmount() { 39 | amountOfFilteredRequests = 0; 40 | if(onOffButton != null) { 41 | String textWihtoutFilterAmount = onOffButton.getText().split(" \\(")[0]; 42 | onOffButton.setText(textWihtoutFilterAmount); 43 | } 44 | } 45 | 46 | public abstract boolean filterRequest(IBurpExtenderCallbacks callbacks, int toolFlag, IRequestInfo requestInfo, IResponseInfo responseInfo); 47 | 48 | public abstract boolean hasStringLiterals(); 49 | 50 | public String[] getFilterStringLiterals() { 51 | return stringLiterals; 52 | } 53 | 54 | public void setFilterStringLiterals(String[] stringLiterals) { 55 | this.stringLiterals = stringLiterals; 56 | if(onOffButton != null) { 57 | onOffButton.setHint(getInfoText()); 58 | } 59 | } 60 | 61 | public void setIsSelected(boolean selected) { 62 | onOffButton.setSelected(selected); 63 | } 64 | 65 | public String toJson() { 66 | String json = "{\"filterIndex\":"+filterIndex+",\"isSelected\":"+onOffButton.isSelected(); 67 | if(!hasStringLiterals()) { 68 | json = json + "}"; 69 | } 70 | else { 71 | json = json + ",\"stringLiterals\":["; 72 | for(int i=0; i" + getDescription() + "
" 89 | + GenericHelper.getArrayAsString(getFilterStringLiterals()) + ""; 90 | } else { 91 | return getDescription(); 92 | } 93 | } 94 | return ""; 95 | } 96 | 97 | public int getFilterIndex() { 98 | return filterIndex; 99 | } 100 | 101 | public String getDescription() { 102 | return description; 103 | } 104 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/dialog/SettingsDialog.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.dialog; 2 | 3 | import java.awt.Component; 4 | import java.awt.FlowLayout; 5 | import java.awt.GridLayout; 6 | import java.awt.event.FocusAdapter; 7 | import java.awt.event.FocusEvent; 8 | import javax.swing.JButton; 9 | import javax.swing.JCheckBox; 10 | import javax.swing.JDialog; 11 | import javax.swing.JLabel; 12 | import javax.swing.JPanel; 13 | import javax.swing.JSpinner; 14 | import javax.swing.SpinnerNumberModel; 15 | import javax.swing.WindowConstants; 16 | import javax.swing.border.EmptyBorder; 17 | import javax.swing.event.ChangeEvent; 18 | import javax.swing.event.ChangeListener; 19 | 20 | import com.protect7.authanalyzer.gui.util.PlaceholderTextField; 21 | import com.protect7.authanalyzer.util.Globals; 22 | import com.protect7.authanalyzer.util.Setting; 23 | import com.protect7.authanalyzer.util.Setting.Item; 24 | 25 | public class SettingsDialog extends JDialog { 26 | 27 | private static final long serialVersionUID = -1481627857573067086L; 28 | private final GridLayout layout; 29 | 30 | public SettingsDialog(Component parent) { 31 | setTitle(Globals.EXTENSION_NAME + " - Settings"); 32 | JPanel dialogPanel = (JPanel) getContentPane(); 33 | dialogPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); 34 | layout = new GridLayout(1, 2, 5, 5); 35 | dialogPanel.setLayout(layout); 36 | 37 | for(Item item : Setting.Item.values()) { 38 | addSettingElement(item); 39 | } 40 | 41 | add(new JLabel("")); 42 | JButton closeButton = new JButton("OK"); 43 | closeButton.addActionListener(e -> dispose()); 44 | JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); 45 | buttonPanel.add(closeButton); 46 | add(buttonPanel); 47 | 48 | setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 49 | setVisible(true); 50 | pack(); 51 | setLocationRelativeTo(parent); 52 | } 53 | 54 | private void addSettingElement(Item item) { 55 | layout.setRows(layout.getRows()+1); 56 | add(new JLabel(item.getDescription() + ": ")); 57 | if(item.getType() == Setting.Type.ARRAY || item.getType() == Setting.Type.STRING) { 58 | PlaceholderTextField inputField = new PlaceholderTextField(); 59 | String currentValue = Setting.getValueAsString(item); 60 | inputField.setText(currentValue); 61 | inputField.addFocusListener(new FocusAdapter() { 62 | @Override 63 | public void focusLost(FocusEvent e) { 64 | super.focusLost(e); 65 | Setting.setValue(item, inputField.getText()); 66 | } 67 | }); 68 | add(inputField); 69 | } 70 | if(item.getType() == Setting.Type.BOOLEAN) { 71 | JCheckBox checkBox = new JCheckBox(); 72 | boolean currentValue = Setting.getValueAsBoolean(item); 73 | checkBox.setSelected(currentValue); 74 | checkBox.addActionListener(e -> Setting.setValue(item, String.valueOf(checkBox.isSelected()))); 75 | add(checkBox); 76 | } 77 | if(item.getType() == Setting.Type.INTEGER) { 78 | JSpinner integerField = new JSpinner(); 79 | ((SpinnerNumberModel) integerField.getModel()).setMinimum(item.getRange().getMinimum()); 80 | ((SpinnerNumberModel) integerField.getModel()).setMaximum(item.getRange().getMaximum()); 81 | ((SpinnerNumberModel) integerField.getModel()).setStepSize(1); 82 | int currentValue = Setting.getValueAsInteger(item); 83 | integerField.setValue(new Integer(currentValue)); 84 | integerField.addChangeListener(new ChangeListener() { 85 | 86 | @Override 87 | public void stateChanged(ChangeEvent e) { 88 | Setting.setValue(item, String.valueOf(integerField.getValue())); 89 | } 90 | }); 91 | add(integerField); 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/util/HintCheckBox.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.util; 2 | 3 | import java.awt.Color; 4 | import java.awt.Dimension; 5 | import java.awt.Point; 6 | import java.awt.GraphicsDevice; 7 | import java.awt.GraphicsEnvironment; 8 | import java.awt.GraphicsConfiguration; 9 | import java.awt.event.ActionListener; 10 | import java.awt.event.MouseAdapter; 11 | import java.awt.event.MouseEvent; 12 | import java.util.stream.Stream; 13 | import javax.swing.BorderFactory; 14 | import javax.swing.Box; 15 | import javax.swing.BoxLayout; 16 | import javax.swing.ImageIcon; 17 | import javax.swing.JCheckBox; 18 | import javax.swing.JDialog; 19 | import javax.swing.JLabel; 20 | import javax.swing.JPanel; 21 | import javax.swing.border.EmptyBorder; 22 | import javax.swing.border.LineBorder; 23 | 24 | public class HintCheckBox extends JPanel { 25 | 26 | private static final long serialVersionUID = -1192483759892519805L; 27 | private final JCheckBox checkBox; 28 | private final JDialog dialog = new JDialog(); 29 | private final JLabel textLabel = new JLabel(); 30 | 31 | public HintCheckBox(String text) { 32 | checkBox = new JCheckBox(text); 33 | setup(""); 34 | } 35 | 36 | public HintCheckBox(String text, String hint) { 37 | checkBox = new JCheckBox(text); 38 | setup(hint); 39 | } 40 | 41 | public HintCheckBox(String text, boolean selected, String hint) { 42 | checkBox = new JCheckBox(text, selected); 43 | setup(hint); 44 | } 45 | 46 | private void setup(String hint) { 47 | BoxLayout layout = new BoxLayout(this, BoxLayout.X_AXIS); 48 | setLayout(layout); 49 | setAlignmentX(JPanel.LEFT_ALIGNMENT); 50 | add(checkBox); 51 | add(Box.createRigidArea(new Dimension(5, 0))); 52 | ImageIcon hintIcon = new ImageIcon(HintCheckBox.class.getClassLoader().getResource("info_icon.png")); 53 | JLabel iconLabel = new JLabel(hintIcon); 54 | add(iconLabel); 55 | dialog.setUndecorated(true); 56 | setHint(hint); 57 | textLabel.setBorder(BorderFactory.createCompoundBorder(new LineBorder(Color.LIGHT_GRAY, 1, true), new EmptyBorder(3, 3, 3, 3))); 58 | dialog.add(textLabel); 59 | iconLabel.addMouseListener(new MouseAdapter() { 60 | @Override 61 | public void mouseEntered(MouseEvent e) { 62 | dialog.repaint(); 63 | dialog.pack(); 64 | int xPos = (int)iconLabel.getLocationOnScreen().getX() + iconLabel.getWidth(); 65 | int yPos = (int)iconLabel.getLocationOnScreen().getY() + iconLabel.getHeight(); 66 | dialog.setLocation(new Point(xPos, yPos)); 67 | dialog.setVisible(true); 68 | // Correct dialog location if it is shown out of screen 69 | GraphicsDevice[] devices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); 70 | int leftDisplayBorder = Stream. 71 | of(devices). 72 | map(GraphicsDevice::getDefaultConfiguration). 73 | map(GraphicsConfiguration::getBounds). 74 | mapToInt(bounds -> bounds.x + bounds.width). 75 | max(). 76 | orElse(0); 77 | int rightPoint = (int)dialog.getLocationOnScreen().getX()+dialog.getWidth(); 78 | while (rightPoint > leftDisplayBorder) { 79 | rightPoint = rightPoint - 10; 80 | xPos = xPos - 10; 81 | } 82 | dialog.setLocation(new Point(xPos, yPos)); 83 | } 84 | @Override 85 | public void mouseExited(MouseEvent e) { 86 | dialog.setVisible(false); 87 | } 88 | }); 89 | } 90 | 91 | public void setHint(String hint) { 92 | textLabel.setText(hint); 93 | textLabel.putClientProperty("html.disable", null); 94 | } 95 | 96 | public void addActionListener(ActionListener l) { 97 | checkBox.addActionListener(l); 98 | } 99 | 100 | public String getText() { 101 | return checkBox.getText(); 102 | } 103 | 104 | public void setText(String text) { 105 | checkBox.setText(text); 106 | } 107 | 108 | public boolean isSelected() { 109 | return checkBox.isSelected(); 110 | } 111 | 112 | public void setSelected(boolean selected) { 113 | checkBox.setSelected(selected); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/util/Setting.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.util; 2 | 3 | import com.protect7.authanalyzer.entities.Range; 4 | 5 | import burp.BurpExtender; 6 | 7 | public class Setting { 8 | 9 | private final static String DELIMITER = ","; 10 | 11 | public static String[] getValueAsArray(Item settingItem) { 12 | String value = getPersistentSetting(settingItem.toString()); 13 | if(value == null) { 14 | value = settingItem.defaultValue; 15 | } 16 | if(settingItem.getType() == Type.ARRAY) { 17 | String[] values = value.split(DELIMITER); 18 | for(int i=0; i 0) { 51 | try { 52 | String setup = new String(messages[0].getResponse()); 53 | return setup; 54 | } 55 | catch (Exception e) { 56 | return null; 57 | } 58 | } 59 | return null; 60 | } 61 | 62 | public static void saveMessage(int id, String session, IHttpRequestResponse message) { 63 | 64 | } 65 | 66 | public IHttpRequestResponse loadMessage(int id, String session) { 67 | return null; 68 | } 69 | 70 | private static IHttpRequestResponse getSettingsMessage() { 71 | URL url = null; 72 | try { 73 | url = new URL(HTTPSERVICE.getProtocol(), HTTPSERVICE.getHost(), HTTPSERVICE.getPort(), SETTINGS_PATH); 74 | } catch (MalformedURLException e) { 75 | return null; 76 | } 77 | byte[] request = BurpExtender.callbacks.getHelpers().buildHttpRequest(url); 78 | IHttpRequestResponse message = new IHttpRequestResponse() { 79 | 80 | @Override 81 | public void setResponse(byte[] message) {} 82 | 83 | @Override 84 | public void setRequest(byte[] message) {} 85 | 86 | @Override 87 | public void setHttpService(IHttpService httpService) {} 88 | 89 | @Override 90 | public void setHighlight(String color) {} 91 | 92 | @Override 93 | public void setComment(String comment) {} 94 | 95 | @Override 96 | public byte[] getResponse() { 97 | return getSetupAsJsonString().getBytes(); 98 | } 99 | 100 | @Override 101 | public byte[] getRequest() { 102 | return request; 103 | } 104 | 105 | @Override 106 | public IHttpService getHttpService() { 107 | return HTTPSERVICE; 108 | } 109 | 110 | @Override 111 | public String getHighlight() { 112 | return null; 113 | } 114 | 115 | @Override 116 | public String getComment() { 117 | return null; 118 | } 119 | }; 120 | return message; 121 | } 122 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/util/GenericHelper.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.util; 2 | 3 | import java.awt.Color; 4 | import java.awt.Component; 5 | import java.awt.Frame; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | 9 | import javax.swing.JFrame; 10 | import javax.swing.JTabbedPane; 11 | import javax.swing.Timer; 12 | import com.protect7.authanalyzer.filter.RequestFilter; 13 | import com.protect7.authanalyzer.gui.main.ConfigurationPanel; 14 | import com.protect7.authanalyzer.util.Setting.Item; 15 | import burp.BurpExtender; 16 | import burp.IBurpExtenderCallbacks; 17 | import burp.IHttpRequestResponse; 18 | import burp.IRequestInfo; 19 | import burp.IResponseInfo; 20 | 21 | public class GenericHelper { 22 | 23 | public static void repeatRequests(IHttpRequestResponse[] messages, ConfigurationPanel configurationPanel) { 24 | if(configurationPanel.isPaused()) { 25 | configurationPanel.pauseButtonPressed(); 26 | } 27 | if(!CurrentConfig.getCurrentConfig().isRunning()) { 28 | configurationPanel.startStopButtonPressed(); 29 | } 30 | if(CurrentConfig.getCurrentConfig().isRunning()) { 31 | boolean applyFilters = Setting.getValueAsBoolean(Item.APPLY_FILTER_ON_MANUAL_REPEAT); 32 | for(IHttpRequestResponse message : messages) { 33 | boolean isFiltered = false; 34 | if(applyFilters) { 35 | IRequestInfo requestInfo = BurpExtender.callbacks.getHelpers().analyzeRequest(message); 36 | IResponseInfo responseInfo = null; 37 | if(message.getResponse() != null) { 38 | responseInfo = BurpExtender.callbacks.getHelpers().analyzeResponse(message.getResponse()); 39 | } 40 | for(int i=0; i { 82 | // JTabbedPane Title Color must be changed with 'setBackgorundAt' for some reason 83 | burpTabbedPane.setBackgroundAt(id, currentColor); 84 | }); 85 | timer.setRepeats(false); 86 | timer.start(); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | public static Color getErrorBgColor() { 94 | return new Color(255, 102, 102); 95 | } 96 | 97 | public static String getArrayAsString(String[] array) { 98 | String arrayAsString = ""; 99 | if (array != null) { 100 | for (String arrayPart : array) { 101 | if (arrayAsString.equals("")) { 102 | arrayAsString = arrayPart; 103 | } else { 104 | arrayAsString += ", " + arrayPart; 105 | } 106 | } 107 | } 108 | return arrayAsString; 109 | } 110 | 111 | public static JFrame getBurpFrame() { 112 | for (Frame f : Frame.getFrames()) { 113 | if (f.isVisible() && f.getTitle().startsWith(("Burp Suite"))) { 114 | return (JFrame) f; 115 | } 116 | } 117 | return null; 118 | } 119 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/TokenBuilder.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | import java.util.EnumSet; 4 | 5 | public class TokenBuilder { 6 | 7 | private String name = null; 8 | private String value = null; 9 | private String extractName = null; 10 | private String grepFromString = null; 11 | private String grepToString = null; 12 | private boolean remove = false; 13 | private boolean autoExtract = false; 14 | private boolean staticValue = false; 15 | private boolean fromToString = false; 16 | private boolean promptForInput = false; 17 | private EnumSet tokenLocationSet = EnumSet.allOf(TokenLocation.class); 18 | private EnumSet autoExtractLocationSet = AutoExtractLocation.getDefaultSet(); 19 | private EnumSet fromToExtractLocationSet = FromToExtractLocation.getDefaultSet(); 20 | private boolean caseSensitiveTokenName = true; 21 | private boolean addIfNotExists = false; 22 | private boolean urlEncoded = true; 23 | private boolean urlDecoded = false; 24 | private String aliases = ""; 25 | 26 | public Token build() { 27 | return new Token(this); 28 | } 29 | 30 | public String getName() { 31 | return name; 32 | } 33 | public TokenBuilder setName(String name) { 34 | this.name = name; 35 | return this; 36 | } 37 | public String getValue() { 38 | return value; 39 | } 40 | public TokenBuilder setValue(String value) { 41 | this.value = value; 42 | return this; 43 | } 44 | public String getAliases() { 45 | return this.aliases; 46 | } 47 | public TokenBuilder setAliases(String value) { 48 | this.aliases = value; 49 | return this; 50 | } 51 | public String getExtractName() { 52 | return extractName; 53 | } 54 | public TokenBuilder setExtractName(String extractName) { 55 | this.extractName = extractName; 56 | return this; 57 | } 58 | public String getGrepFromString() { 59 | return grepFromString; 60 | } 61 | public TokenBuilder setGrepFromString(String grepFromString) { 62 | this.grepFromString = grepFromString; 63 | return this; 64 | } 65 | public String getGrepToString() { 66 | return grepToString; 67 | } 68 | public TokenBuilder setGrepToString(String grepToString) { 69 | this.grepToString = grepToString; 70 | return this; 71 | } 72 | public boolean isRemove() { 73 | return remove; 74 | } 75 | public TokenBuilder setIsRemove(boolean remove) { 76 | this.remove = remove; 77 | return this; 78 | } 79 | public boolean isAutoExtract() { 80 | return autoExtract; 81 | } 82 | public TokenBuilder setIsAutoExtract(boolean autoExtract) { 83 | this.autoExtract = autoExtract; 84 | return this; 85 | } 86 | public boolean isStaticValue() { 87 | return staticValue; 88 | } 89 | public TokenBuilder setIsStaticValue(boolean staticValue) { 90 | this.staticValue = staticValue; 91 | return this; 92 | } 93 | public boolean isFromToString() { 94 | return fromToString; 95 | } 96 | public TokenBuilder setIsFromToString(boolean fromToString) { 97 | this.fromToString = fromToString; 98 | return this; 99 | } 100 | public boolean isPromptForInput() { 101 | return promptForInput; 102 | } 103 | public TokenBuilder setIsPromptForInput(boolean promptForInput) { 104 | this.promptForInput = promptForInput; 105 | return this; 106 | } 107 | public EnumSet getTokenLocationSet() { 108 | return tokenLocationSet; 109 | } 110 | public TokenBuilder setTokenLocationSet(EnumSet tokenLocationSet) { 111 | this.tokenLocationSet = tokenLocationSet; 112 | return this; 113 | } 114 | public EnumSet getAutoExtractLocationSet() { 115 | return autoExtractLocationSet; 116 | } 117 | public TokenBuilder setAutoExtractLocationSet(EnumSet autoExtractLocationSet) { 118 | this.autoExtractLocationSet = autoExtractLocationSet; 119 | return this; 120 | } 121 | public EnumSet getFromToExtractLocationSet() { 122 | return fromToExtractLocationSet; 123 | } 124 | public TokenBuilder setFromToExtractLocationSet(EnumSet fromToExtractLocationSet) { 125 | this.fromToExtractLocationSet = fromToExtractLocationSet; 126 | return this; 127 | } 128 | public boolean isCaseSensitiveTokenName() { 129 | return caseSensitiveTokenName; 130 | } 131 | public TokenBuilder setIsCaseSensitiveTokenName(boolean caseSensitiveTokenName) { 132 | this.caseSensitiveTokenName = caseSensitiveTokenName; 133 | return this; 134 | } 135 | public boolean isAddIfNotExists() { 136 | return addIfNotExists; 137 | } 138 | public TokenBuilder setIsAddIfNotExists(boolean addIfNotExists) { 139 | this.addIfNotExists = addIfNotExists; 140 | return this; 141 | } 142 | public boolean isUrlEncoded() { 143 | return urlEncoded; 144 | } 145 | public TokenBuilder setIsUrlEncoded(boolean urlEncoded) { 146 | this.urlEncoded = urlEncoded; 147 | return this; 148 | } 149 | 150 | public boolean isUrlDecoded() { 151 | return urlDecoded; 152 | } 153 | public TokenBuilder setIsUrlDecoded(boolean urlDecoded) { 154 | this.urlDecoded = urlDecoded; 155 | return this; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/main/RequestResponsePanel.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.main; 2 | 3 | import java.awt.Component; 4 | import java.util.HashMap; 5 | import javax.swing.JPanel; 6 | import javax.swing.JTabbedPane; 7 | 8 | import com.protect7.authanalyzer.entities.Session; 9 | import com.protect7.authanalyzer.util.CurrentConfig; 10 | import burp.IMessageEditor; 11 | 12 | public class RequestResponsePanel extends JTabbedPane { 13 | 14 | private static final long serialVersionUID = 5940984512441844430L; 15 | public final String TITLE_ORIGINAL = "Original"; 16 | private final HashMap sessionTabbedPaneMap = new HashMap(); 17 | private final CenterPanel centerPanel; 18 | private final int paneId; 19 | private int selectedIndex = 0; 20 | 21 | public RequestResponsePanel(int paneId, CenterPanel centerPanel) { 22 | this.paneId = paneId; 23 | this.centerPanel = centerPanel; 24 | init(); 25 | addChangeListener(e -> { 26 | SessionTabbedPane sessionTabbedPane = getSelectedSessionTabbedPane(); 27 | if(sessionTabbedPane != null && sessionTabbedPane.getTabCount() == 2) { 28 | if(sessionTabbedPane.getSelectedIndex() != selectedIndex) { 29 | sessionTabbedPane.setSelectedIndex(selectedIndex); 30 | } 31 | else { 32 | centerPanel.updateDiffPane(); 33 | } 34 | } 35 | }); 36 | } 37 | 38 | public void init() { 39 | removeAll(); 40 | SessionTabbedPane originalSessionTabbedPane = new SessionTabbedPane(TITLE_ORIGINAL); 41 | add(TITLE_ORIGINAL, originalSessionTabbedPane); 42 | sessionTabbedPaneMap.put(TITLE_ORIGINAL, originalSessionTabbedPane); 43 | for(Session session : CurrentConfig.getCurrentConfig().getSessions()) { 44 | SessionTabbedPane sessionTabbedPane = new SessionTabbedPane(session.getName()); 45 | add(session.getName(), sessionTabbedPane); 46 | sessionTabbedPaneMap.put(session.getName(), sessionTabbedPane); 47 | } 48 | if(paneId == 1 && getTabCount() > 1) { 49 | setSelectedIndex(1); 50 | } 51 | } 52 | 53 | public void setRequestMessage(String sessionName, Component component, IMessageEditor messageEditor) { 54 | if(sessionTabbedPaneMap.containsKey(sessionName)) { 55 | sessionTabbedPaneMap.get(sessionName).setRequestMessage(component, messageEditor); 56 | } 57 | } 58 | 59 | public void setResponseMessage(String sessionName, Component component, IMessageEditor messageEditor) { 60 | if(sessionTabbedPaneMap.containsKey(sessionName)) { 61 | sessionTabbedPaneMap.get(sessionName).setResponseMessage(component, messageEditor); 62 | } 63 | } 64 | 65 | public String getSelectedSession() { 66 | return getTitleAt(getSelectedIndex()); 67 | } 68 | 69 | public String getSelectedMessage() { 70 | SessionTabbedPane sessionTabbedPane = getSelectedSessionTabbedPane(); 71 | if(sessionTabbedPane != null) { 72 | return sessionTabbedPane.getTitleAt(sessionTabbedPane.getSelectedIndex()); 73 | } 74 | return null; 75 | } 76 | 77 | public SessionTabbedPane getSelectedSessionTabbedPane() { 78 | return (SessionTabbedPane) getSelectedComponent(); 79 | } 80 | 81 | public String getCurrentMessageString() { 82 | SessionTabbedPane sessionTabbedPane = getSelectedSessionTabbedPane(); 83 | if(sessionTabbedPane != null) { 84 | return sessionTabbedPane.getCurrentMessageString(); 85 | } 86 | return null; 87 | } 88 | 89 | public boolean setTabbedPaneIndex(int index) { 90 | SessionTabbedPane sessionTabbedPane = getSelectedSessionTabbedPane(); 91 | if(sessionTabbedPane != null) { 92 | if(sessionTabbedPane.getSelectedIndex() != index) { 93 | if(sessionTabbedPane.getTabCount() > index) { 94 | sessionTabbedPane.setSelectedIndex(index); 95 | return true; 96 | } 97 | } 98 | } 99 | return false; 100 | } 101 | 102 | private class SessionTabbedPane extends JTabbedPane { 103 | 104 | private static final long serialVersionUID = -4100725845615986632L; 105 | private final String TITLE_REQUEST = "Request"; 106 | private final String TITLE_RESPONSE = "Response"; 107 | private IMessageEditor requestMessageEditor = null; 108 | private IMessageEditor responseMessageEditor = null; 109 | 110 | public SessionTabbedPane(String name) { 111 | add(TITLE_REQUEST, new JPanel()); 112 | add(TITLE_RESPONSE, new JPanel()); 113 | addChangeListener(e -> { 114 | selectedIndex = getSelectedIndex(); 115 | centerPanel.updateOtherTabbedPane(paneId, getSelectedIndex()); 116 | }); 117 | } 118 | 119 | public void setRequestMessage(Component component, IMessageEditor messageEditor) { 120 | requestMessageEditor = messageEditor; 121 | setComponentAt(0, component); 122 | } 123 | 124 | public void setResponseMessage(Component component, IMessageEditor messageEditor) { 125 | responseMessageEditor = messageEditor; 126 | setComponentAt(1, component); 127 | } 128 | 129 | public String getCurrentMessageString() { 130 | if(getSelectedIndex() == 0) { 131 | if(requestMessageEditor != null) { 132 | return new String(requestMessageEditor.getMessage()); 133 | } 134 | } 135 | if(getSelectedIndex() == 1) { 136 | if(responseMessageEditor != null) { 137 | return new String(responseMessageEditor.getMessage()); 138 | } 139 | } 140 | return null; 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/dialog/DataExportDialog.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.dialog; 2 | 3 | import java.io.File; 4 | import java.util.ArrayList; 5 | import java.util.EnumSet; 6 | import javax.swing.BoxLayout; 7 | import javax.swing.ButtonGroup; 8 | import javax.swing.JCheckBox; 9 | import javax.swing.JFileChooser; 10 | import javax.swing.JLabel; 11 | import javax.swing.JOptionPane; 12 | import javax.swing.JPanel; 13 | import javax.swing.JRadioButton; 14 | import javax.swing.JSeparator; 15 | import com.protect7.authanalyzer.entities.OriginalRequestResponse; 16 | import com.protect7.authanalyzer.gui.main.CenterPanel; 17 | import com.protect7.authanalyzer.util.CurrentConfig; 18 | import com.protect7.authanalyzer.util.DataExporter; 19 | 20 | public class DataExportDialog { 21 | 22 | public DataExportDialog(CenterPanel centerPanel) { 23 | JPanel inputPanel = new JPanel(); 24 | inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.PAGE_AXIS)); 25 | 26 | inputPanel.add(new JLabel("Choose the format of the export.")); 27 | JRadioButton htmlReport = new JRadioButton("HTML Export", true); 28 | JRadioButton xmlReport = new JRadioButton("XML Export"); 29 | ButtonGroup group = new ButtonGroup(); 30 | group.add(htmlReport); 31 | group.add(xmlReport); 32 | inputPanel.add(htmlReport); 33 | inputPanel.add(xmlReport); 34 | JCheckBox doBase64Encode = new JCheckBox("Base64-encode requests and responses", true); 35 | doBase64Encode.setEnabled(false); 36 | htmlReport.addActionListener(e -> doBase64Encode.setEnabled(false)); 37 | xmlReport.addActionListener(e -> doBase64Encode.setEnabled(true)); 38 | inputPanel.add(doBase64Encode); 39 | inputPanel.add(new JLabel(" ")); 40 | inputPanel.add(new JSeparator(JSeparator.HORIZONTAL)); 41 | inputPanel.add(new JLabel(" ")); 42 | 43 | inputPanel.add(new JLabel("Select Columns to include in export.")); 44 | 45 | EnumSet mainColumns = EnumSet.allOf(DataExporter.MainColumn.class); 46 | for(DataExporter.MainColumn mainColumn : DataExporter.MainColumn.values()) { 47 | JCheckBox checkBox = new JCheckBox(mainColumn.getName(), true); 48 | checkBox.addActionListener(e -> { 49 | if(checkBox.isSelected()) { 50 | mainColumns.add(mainColumn); 51 | } 52 | else { 53 | mainColumns.remove(mainColumn); 54 | } 55 | }); 56 | inputPanel.add(checkBox); 57 | } 58 | EnumSet sessionColumns = EnumSet.allOf(DataExporter.SessionColumn.class); 59 | for(DataExporter.SessionColumn sessionColumn : DataExporter.SessionColumn.values()) { 60 | JCheckBox checkBox; 61 | if(sessionColumn == DataExporter.SessionColumn.REQUEST || sessionColumn == DataExporter.SessionColumn.RESPONSE) { 62 | checkBox = new JCheckBox(sessionColumn.getName(), false); 63 | sessionColumns.remove(sessionColumn); 64 | } 65 | else { 66 | checkBox = new JCheckBox(sessionColumn.getName(), true); 67 | } 68 | checkBox.addActionListener(e -> { 69 | if(checkBox.isSelected()) { 70 | sessionColumns.add(sessionColumn); 71 | } 72 | else { 73 | sessionColumns.remove(sessionColumn); 74 | } 75 | }); 76 | inputPanel.add(checkBox); 77 | } 78 | inputPanel.add(new JLabel(" ")); 79 | 80 | int result = JOptionPane.showConfirmDialog(centerPanel, inputPanel, "Export Table Data", 81 | JOptionPane.OK_CANCEL_OPTION); 82 | if (result == JOptionPane.OK_OPTION) { 83 | JFileChooser chooser = new JFileChooser(); 84 | if(htmlReport.isSelected()) { 85 | chooser.setSelectedFile(new File("Auth_Analyzer_Report.html")); 86 | } 87 | else { 88 | chooser.setSelectedFile(new File("Auth_Analyzer_Report.xml")); 89 | } 90 | int status = chooser.showSaveDialog(centerPanel); 91 | if(status == JFileChooser.APPROVE_OPTION) { 92 | File file = chooser.getSelectedFile(); 93 | if(!file.getName().endsWith(".html") || !file.getName().endsWith(".xml")) { 94 | String newFileName; 95 | if(file.getName().lastIndexOf(".") != -1) { 96 | int index = file.getAbsolutePath().lastIndexOf("."); 97 | newFileName = file.getAbsolutePath().substring(0, index); 98 | } 99 | else { 100 | newFileName = file.getAbsolutePath(); 101 | } 102 | if(htmlReport.isSelected()) { 103 | newFileName = newFileName + ".html"; 104 | } 105 | else { 106 | newFileName = newFileName + ".xml"; 107 | } 108 | file = new File(newFileName); 109 | } 110 | ArrayList filteredRequestResponseList = centerPanel.getFilteredRequestResponseList(); 111 | boolean success = false; 112 | if(htmlReport.isSelected()) { 113 | success = DataExporter.getDataExporter().createHTML(file, filteredRequestResponseList, CurrentConfig.getCurrentConfig().getSessions(), 114 | mainColumns, sessionColumns); 115 | } 116 | else { 117 | success = DataExporter.getDataExporter().createXML(file, filteredRequestResponseList, CurrentConfig.getCurrentConfig().getSessions(), 118 | mainColumns, sessionColumns, doBase64Encode.isSelected()); 119 | } 120 | if(success) { 121 | JOptionPane.showMessageDialog(centerPanel, "Successfully exported to\n" + file.getAbsolutePath()); 122 | } 123 | else { 124 | JOptionPane.showMessageDialog(centerPanel, "Failed to export data"); 125 | } 126 | } 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/dialog/MatchAndReplaceDialog.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.dialog; 2 | 3 | import java.awt.Component; 4 | import java.awt.GridBagConstraints; 5 | import java.awt.GridBagLayout; 6 | import java.awt.Insets; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | import java.awt.event.WindowAdapter; 10 | import java.awt.event.WindowEvent; 11 | import java.util.ArrayList; 12 | import java.util.Iterator; 13 | import javax.swing.ImageIcon; 14 | import javax.swing.JButton; 15 | import javax.swing.JDialog; 16 | import javax.swing.JLabel; 17 | import javax.swing.JPanel; 18 | import javax.swing.SwingUtilities; 19 | import javax.swing.WindowConstants; 20 | import javax.swing.border.EmptyBorder; 21 | import com.protect7.authanalyzer.entities.MatchAndReplace; 22 | import com.protect7.authanalyzer.gui.entity.SessionPanel; 23 | import com.protect7.authanalyzer.gui.util.PlaceholderTextField; 24 | 25 | public class MatchAndReplaceDialog extends JDialog { 26 | 27 | private static final long serialVersionUID = 7866009243313757748L; 28 | private final int TEXTFIELD_WIDH = 25; 29 | private final JPanel listPanel = (JPanel) getContentPane(); 30 | private final GridBagConstraints c = new GridBagConstraints(); 31 | private final ArrayList matchAndReplaceList; 32 | private final String INFO_TEXT; 33 | private final PlaceholderTextField matchInputText = new PlaceholderTextField(TEXTFIELD_WIDH); 34 | private final PlaceholderTextField replaceInputText = new PlaceholderTextField(TEXTFIELD_WIDH); 35 | private final JButton addEntryButton = new JButton("\u2795"); 36 | private final JButton okButton = new JButton("OK"); 37 | 38 | public MatchAndReplaceDialog(SessionPanel sessionPanel) { 39 | matchAndReplaceList = sessionPanel.getMatchAndReplaceList(); 40 | INFO_TEXT = "Specify Match and Replace rules (string literals) for all repeated requests of the session \""+sessionPanel.getSessionName()+"\""; 41 | listPanel.setLayout(new GridBagLayout()); 42 | listPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); 43 | 44 | addEntryButton.addActionListener(new ActionListener() { 45 | 46 | @Override 47 | public void actionPerformed(ActionEvent e) { 48 | addMatchAndReplace(matchInputText.getText(), replaceInputText.getText()); 49 | updateMatchAndReplaceList(); 50 | SwingUtilities.getWindowAncestor((Component) e.getSource()).pack(); 51 | } 52 | }); 53 | updateMatchAndReplaceList(); 54 | setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 55 | setVisible(true); 56 | setTitle("Match and Replace for Session " + sessionPanel.getSessionName()); 57 | pack(); 58 | setLocationRelativeTo(sessionPanel); 59 | 60 | okButton.addActionListener(e -> { 61 | addMatchAndReplace(matchInputText.getText(), replaceInputText.getText()); 62 | dispose(); 63 | }); 64 | 65 | addWindowListener(new WindowAdapter() { 66 | @Override 67 | public void windowClosed(WindowEvent e) { 68 | sessionPanel.updateMatchAndReplaceButtonText(); 69 | } 70 | }); 71 | } 72 | 73 | private void updateMatchAndReplaceList() { 74 | listPanel.removeAll(); 75 | c.fill = GridBagConstraints.HORIZONTAL; 76 | c.insets = new Insets(0, 5, 20, 0); 77 | c.gridx = 0; 78 | c.gridy = 0; 79 | c.gridwidth = 3; 80 | listPanel.add(new JLabel(INFO_TEXT), c); 81 | c.insets = new Insets(0, 5, 5, 0); 82 | c.gridwidth = 1; 83 | c.gridy++; 84 | listPanel.add(new JLabel("Match:"), c); 85 | c.gridx = 1; 86 | listPanel.add(new JLabel("Replace:"), c); 87 | c.gridx = 0; 88 | c.gridy++; 89 | listPanel.add(matchInputText, c); 90 | c.gridx = 1; 91 | listPanel.add(replaceInputText, c); 92 | c.gridx = 2; 93 | listPanel.add(addEntryButton, c); 94 | 95 | c.gridy++; 96 | for (MatchAndReplace matchAndReplace : matchAndReplaceList) { 97 | c.gridx = 0; 98 | listPanel.add(getFormattedLabel(matchAndReplace.getMatch()), c); 99 | c.gridx = 1; 100 | listPanel.add(getFormattedLabel(matchAndReplace.getReplace()), c); 101 | JButton deleteEntryBtn = new JButton(); 102 | deleteEntryBtn.setIcon(new ImageIcon(this.getClass().getClassLoader().getResource("delete.png"))); 103 | deleteEntryBtn.addActionListener(new ActionListener() { 104 | 105 | @Override 106 | public void actionPerformed(ActionEvent e) { 107 | removeGivenMatch(matchAndReplace.getMatch()); 108 | updateMatchAndReplaceList(); 109 | SwingUtilities.getWindowAncestor((Component) e.getSource()).pack(); 110 | } 111 | }); 112 | c.gridx = 2; 113 | listPanel.add(deleteEntryBtn, c); 114 | c.gridy++; 115 | } 116 | c.insets = new Insets(10, 5, 10, 0); 117 | listPanel.add(okButton, c); 118 | listPanel.revalidate(); 119 | listPanel.repaint(); 120 | pack(); 121 | } 122 | 123 | private JLabel getFormattedLabel(String text) { 124 | String formattedText; 125 | if(text.length() > 28) { 126 | formattedText = text.substring(0, 25) + "..."; 127 | } 128 | else { 129 | formattedText = text; 130 | } 131 | JLabel label = new JLabel(formattedText); 132 | label.setToolTipText(text); 133 | return label; 134 | } 135 | 136 | private void addMatchAndReplace(String matchText, String replaceText) { 137 | if (!matchText.equals("") && !replaceText.equals("")) { 138 | removeGivenMatch(matchText); 139 | matchAndReplaceList.add(new MatchAndReplace(matchText, replaceText)); 140 | } 141 | } 142 | 143 | private boolean removeGivenMatch(String match) { 144 | Iterator it = matchAndReplaceList.iterator(); 145 | while(it.hasNext()) { 146 | MatchAndReplace m = it.next(); 147 | if(m.getMatch().equals(match)) { 148 | it.remove(); 149 | return true; 150 | } 151 | } 152 | return false; 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/util/CustomRowSorter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.util; 2 | 3 | import java.util.Collections; 4 | import javax.swing.JCheckBox; 5 | import javax.swing.RowFilter; 6 | import javax.swing.RowSorter; 7 | import javax.swing.SortOrder; 8 | import javax.swing.table.TableRowSorter; 9 | import com.protect7.authanalyzer.entities.AnalyzerRequestResponse; 10 | import com.protect7.authanalyzer.entities.OriginalRequestResponse; 11 | import com.protect7.authanalyzer.entities.Session; 12 | import com.protect7.authanalyzer.gui.main.CenterPanel; 13 | import com.protect7.authanalyzer.util.BypassConstants; 14 | import com.protect7.authanalyzer.util.CurrentConfig; 15 | 16 | public class CustomRowSorter extends TableRowSorter { 17 | 18 | public CustomRowSorter(CenterPanel centerPanel, RequestTableModel tableModel, JCheckBox showOnlyMarked, JCheckBox showDuplicates, JCheckBox showBypassed, 19 | JCheckBox showPotentialBypassed, JCheckBox showNotBypassed, JCheckBox showNA, PlaceholderTextField filterText, 20 | JCheckBox searchInPath, JCheckBox searchInRequest, JCheckBox searchInResponse, JCheckBox negativeSearch) { 21 | super(tableModel); 22 | showOnlyMarked.addActionListener(e -> tableModel.fireTableDataChanged()); 23 | showDuplicates.addActionListener(e -> tableModel.fireTableDataChanged()); 24 | showBypassed.addActionListener(e -> tableModel.fireTableDataChanged()); 25 | showPotentialBypassed.addActionListener(e -> tableModel.fireTableDataChanged()); 26 | showNotBypassed.addActionListener(e -> tableModel.fireTableDataChanged()); 27 | showNA.addActionListener(e -> tableModel.fireTableDataChanged()); 28 | filterText.addActionListener(e -> tableModel.fireTableDataChanged()); 29 | setMaxSortKeys(1); 30 | setSortKeys(Collections.singletonList(new RowSorter.SortKey(0, SortOrder.DESCENDING))); 31 | 32 | 33 | RowFilter filter = new RowFilter() { 34 | 35 | public boolean include(Entry entry) { 36 | if(filterText.getText() != null && !filterText.getText().equals("")) { 37 | centerPanel.toggleSearchButtonText(); 38 | boolean doShow = false; 39 | if(searchInPath.isSelected()) { 40 | boolean contained = entry.getStringValue(3).toString().contains(filterText.getText()); 41 | if((contained && !negativeSearch.isSelected()) || (!contained && negativeSearch.isSelected())) { 42 | doShow = true; 43 | } 44 | } 45 | if(searchInRequest.isSelected() && !doShow) { 46 | try { 47 | int id = Integer.parseInt(entry.getStringValue(0)); 48 | for (Session session : CurrentConfig.getCurrentConfig().getSessions()) { 49 | AnalyzerRequestResponse analyzerRequestResponse = session.getRequestResponseMap().get(id); 50 | if(analyzerRequestResponse.getRequestResponse().getRequest() != null) { 51 | String response = new String(analyzerRequestResponse.getRequestResponse().getRequest()); 52 | boolean contained = response.contains(filterText.getText()); 53 | if((contained && !negativeSearch.isSelected()) || (!contained && negativeSearch.isSelected())) { 54 | doShow = true; 55 | break; 56 | } 57 | } 58 | } 59 | } 60 | catch (Exception e) { 61 | e.printStackTrace(); 62 | } 63 | } 64 | if(searchInResponse.isSelected() && !doShow) { 65 | try { 66 | int id = Integer.parseInt(entry.getStringValue(0)); 67 | for (Session session : CurrentConfig.getCurrentConfig().getSessions()) { 68 | AnalyzerRequestResponse analyzerRequestResponse = session.getRequestResponseMap().get(id); 69 | if(analyzerRequestResponse.getRequestResponse().getResponse() != null) { 70 | String response = new String(analyzerRequestResponse.getRequestResponse().getResponse()); 71 | boolean contained = response.contains(filterText.getText()); 72 | if((contained && !negativeSearch.isSelected()) || (!contained && negativeSearch.isSelected())) { 73 | doShow = true; 74 | break; 75 | } 76 | } 77 | } 78 | } 79 | catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | } 83 | centerPanel.toggleSearchButtonText(); 84 | if(!doShow && (searchInPath.isSelected() || searchInResponse.isSelected() || searchInRequest.isSelected())) { 85 | return false; 86 | } 87 | } 88 | if(showOnlyMarked.isSelected()) { 89 | OriginalRequestResponse requestResponse = tableModel.getOriginalRequestResponseById(Integer.parseInt(entry.getStringValue(0))); 90 | if(requestResponse != null && !requestResponse.isMarked()) { 91 | return false; 92 | } 93 | } 94 | if(!showDuplicates.isSelected()) { 95 | String endpoint = entry.getStringValue(1).toString() + entry.getStringValue(2).toString() 96 | + entry.getStringValue(3).toString(); 97 | if(tableModel.isDuplicate(Integer.parseInt(entry.getStringValue(0)), endpoint)) { 98 | return false; 99 | } 100 | } 101 | if(showBypassed.isSelected()) { 102 | for(int i = entry.getValueCount()-1; i>3; i--) { 103 | if(entry.getStringValue(i).equals(BypassConstants.SAME.toString())) { 104 | return true; 105 | } 106 | } 107 | } 108 | if(showPotentialBypassed.isSelected()) { 109 | for(int i = entry.getValueCount()-1; i>3; i--) { 110 | if(entry.getStringValue(i).equals(BypassConstants.SIMILAR.toString())) { 111 | return true; 112 | } 113 | } 114 | } 115 | if(showNotBypassed.isSelected()) { 116 | for(int i = entry.getValueCount()-1; i>3; i--) { 117 | if(entry.getStringValue(i).equals(BypassConstants.DIFFERENT.toString())) { 118 | return true; 119 | } 120 | } 121 | } 122 | if(showNA.isSelected()) { 123 | for(int i = entry.getValueCount()-1; i>3; i--) { 124 | if(entry.getStringValue(i).equals(BypassConstants.NA.toString())) { 125 | return true; 126 | } 127 | } 128 | } 129 | return false; 130 | } 131 | }; 132 | 133 | setRowFilter(filter); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/Session.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | import java.net.URL; 4 | 5 | /** 6 | * This Entity holds a session. 7 | * 8 | * @author Simon Reinhart 9 | */ 10 | 11 | import java.util.ArrayList; 12 | import java.util.HashMap; 13 | import com.google.gson.ExclusionStrategy; 14 | import com.google.gson.FieldAttributes; 15 | import com.protect7.authanalyzer.gui.entity.StatusPanel; 16 | 17 | public class Session { 18 | 19 | private final String name; 20 | private String headersToReplace; 21 | private String headersToRemove; 22 | private boolean removeHeaders; 23 | private boolean filterRequestsWithSameHeader; 24 | private boolean restrictToScope = false; 25 | private boolean testCors = false; 26 | private URL scopeUrl; 27 | private int tabbedPaneRequestIndex; 28 | private int tabbedPaneResponseIndex; 29 | private final HashMap requestResponseMap = new HashMap<>(); 30 | private ArrayList tokens = new ArrayList(); 31 | private ArrayList matchAndReplaceList = new ArrayList(); 32 | private final StatusPanel statusPanel; 33 | 34 | public Session(String name, String headersToReplace, boolean removeHeaders, String headersToRemove, boolean filterRequestsWithSameHeader, boolean restrictToScope, 35 | URL scopeUrl, boolean testCors, ArrayList tokens, ArrayList matchAndReplaceList, StatusPanel statusPanel) { 36 | this.name = name; 37 | this.removeHeaders = removeHeaders; 38 | this.headersToReplace = headersToReplace; 39 | this.filterRequestsWithSameHeader = filterRequestsWithSameHeader; 40 | this.setRestrictToScope(restrictToScope); 41 | this.setTestCors(testCors); 42 | this.headersToRemove = headersToRemove; 43 | this.setScopeUrl(scopeUrl); 44 | this.setTokens(tokens); 45 | this.matchAndReplaceList = matchAndReplaceList; 46 | this.statusPanel = statusPanel; 47 | } 48 | 49 | public String getName() { 50 | return name; 51 | } 52 | 53 | public String getHeadersToReplace() { 54 | return headersToReplace; 55 | } 56 | 57 | public void setHeadersToReplace(String headersToReplace) { 58 | this.headersToReplace = headersToReplace; 59 | } 60 | 61 | public HashMap getRequestResponseMap() { 62 | return requestResponseMap; 63 | } 64 | 65 | public void putRequestResponse(int key, AnalyzerRequestResponse requestResponse) { 66 | requestResponseMap.put(key, requestResponse); 67 | } 68 | 69 | public void clearRequestResponseMap() { 70 | requestResponseMap.clear(); 71 | } 72 | 73 | public int getTabbedPaneRequestIndex() { 74 | return tabbedPaneRequestIndex; 75 | } 76 | 77 | public void setTabbedPaneRequestIndex(int tabbedPaneRequestIndex) { 78 | this.tabbedPaneRequestIndex = tabbedPaneRequestIndex; 79 | } 80 | 81 | public int getTabbedPaneResponseIndex() { 82 | return tabbedPaneResponseIndex; 83 | } 84 | 85 | public void setTabbedPaneResponseIndex(int tabbedPaneResponseIndex) { 86 | this.tabbedPaneResponseIndex = tabbedPaneResponseIndex; 87 | } 88 | 89 | public boolean isFilterRequestsWithSameHeader() { 90 | return filterRequestsWithSameHeader; 91 | } 92 | 93 | public void setFilterRequestsWithSameHeader(boolean filterRequestsWithSameHeader) { 94 | this.filterRequestsWithSameHeader = filterRequestsWithSameHeader; 95 | } 96 | 97 | public StatusPanel getStatusPanel() { 98 | return statusPanel; 99 | } 100 | 101 | public ArrayList getTokens() { 102 | return tokens; 103 | } 104 | 105 | public void setTokens(ArrayList tokens) { 106 | this.tokens = tokens; 107 | } 108 | 109 | public ExclusionStrategy getExclusionStrategy() { 110 | ExclusionStrategy strategy = new ExclusionStrategy() { 111 | 112 | @Override 113 | public boolean shouldSkipField(FieldAttributes field) { 114 | if(field.getDeclaringClass() == Session.class && field.getName().equals("tabbedPaneRequestIndex")) { 115 | return true; 116 | } 117 | if(field.getDeclaringClass() == Session.class && field.getName().equals("tabbedPaneResponseIndex")) { 118 | return true; 119 | } 120 | if(field.getDeclaringClass() == Session.class && field.getName().equals("requestResponseMap")) { 121 | return true; 122 | } 123 | if(field.getDeclaringClass() == Session.class && field.getName().equals("statusPanel")) { 124 | return true; 125 | } 126 | if(field.getDeclaringClass() == Token.class && field.getName().equals("request")) { 127 | return true; 128 | } 129 | return false; 130 | } 131 | 132 | @Override 133 | public boolean shouldSkipClass(Class clazz) { 134 | return false; 135 | } 136 | }; 137 | return strategy; 138 | } 139 | 140 | public boolean isRestrictToScope() { 141 | return restrictToScope; 142 | } 143 | 144 | public void setRestrictToScope(boolean restrictToScope) { 145 | this.restrictToScope = restrictToScope; 146 | } 147 | 148 | public URL getScopeUrl() { 149 | return scopeUrl; 150 | } 151 | 152 | public void setScopeUrl(URL scopeUrl) { 153 | this.scopeUrl = scopeUrl; 154 | } 155 | 156 | public Token getTokenByName(String tokenName) { 157 | for(Token token : tokens) { 158 | if(token.getName().equals(tokenName)) { 159 | return token; 160 | } 161 | } 162 | return null; 163 | } 164 | 165 | public boolean isRemoveHeaders() { 166 | return removeHeaders; 167 | } 168 | 169 | public void setRemoveHeaders(boolean removeHeaders) { 170 | this.removeHeaders = removeHeaders; 171 | } 172 | 173 | public String getHeadersToRemove() { 174 | return headersToRemove; 175 | } 176 | 177 | public void setHeadersToRemove(String headersToRemove) { 178 | this.headersToRemove = headersToRemove; 179 | } 180 | 181 | public boolean isTestCors() { 182 | return testCors; 183 | } 184 | 185 | public void setTestCors(boolean testCors) { 186 | this.testCors = testCors; 187 | } 188 | 189 | public ArrayList getMatchAndReplaceList() { 190 | return matchAndReplaceList; 191 | } 192 | 193 | public void setMatchAndReplaceList(ArrayList matchAndReplaceList) { 194 | this.matchAndReplaceList = matchAndReplaceList; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/util/SessionTabbedPane.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.util; 2 | 3 | import javax.swing.JButton; 4 | import javax.swing.JLabel; 5 | import javax.swing.JMenuItem; 6 | import javax.swing.JOptionPane; 7 | import javax.swing.JPanel; 8 | import javax.swing.JPopupMenu; 9 | import javax.swing.JTabbedPane; 10 | import com.protect7.authanalyzer.gui.listener.CloneSessionListener; 11 | import com.protect7.authanalyzer.gui.listener.DeleteSessionListener; 12 | import com.protect7.authanalyzer.gui.listener.NewSessionListener; 13 | import com.protect7.authanalyzer.gui.listener.RenameSessionListener; 14 | import java.awt.Component; 15 | import java.awt.FlowLayout; 16 | import java.awt.Insets; 17 | import java.awt.event.ActionEvent; 18 | import java.awt.event.ActionListener; 19 | import java.awt.event.MouseAdapter; 20 | import java.awt.event.MouseEvent; 21 | 22 | public class SessionTabbedPane extends JTabbedPane { 23 | 24 | private static final long serialVersionUID = -2210225276859158505L; 25 | private DeleteSessionListener deleteSessionListener = null; 26 | private RenameSessionListener renameSessionListener = null; 27 | private NewSessionListener newSessionListener = null; 28 | private CloneSessionListener cloneSessionListener = null; 29 | private boolean modifEnabled = true; 30 | 31 | public SessionTabbedPane() { 32 | super(); 33 | addTabNewSession(); 34 | } 35 | 36 | public void addDeleteSessionListener(DeleteSessionListener deleteSessionListener) { 37 | this.deleteSessionListener = deleteSessionListener; 38 | } 39 | 40 | public void addRenameSessionListener(RenameSessionListener renameSessionListener) { 41 | this.renameSessionListener = renameSessionListener; 42 | } 43 | 44 | public void addNewSessionListener(NewSessionListener newSessionListener) { 45 | this.newSessionListener = newSessionListener; 46 | } 47 | 48 | public void addCloneSessionListener(CloneSessionListener cloneSessionListener) { 49 | this.cloneSessionListener = cloneSessionListener; 50 | } 51 | 52 | public void setModifEnabled(boolean modifEnabled) { 53 | this.modifEnabled = modifEnabled; 54 | } 55 | 56 | @Override 57 | public void setTitleAt(int index, String title) { 58 | super.setTitleAt(index, title); 59 | setTabComponentAt(index, new SessionTab(null, title, index)); 60 | } 61 | 62 | @Override 63 | public void addTab(String title, Component component) { 64 | int index = getTabCount() - 1; 65 | insertTab(title, null, component, null, index); 66 | setTabComponentAt(index, new SessionTab(component, title, index)); 67 | getTabComponentAt(index).addMouseListener(new MouseAdapter() { 68 | @Override 69 | public void mouseClicked(MouseEvent e) { 70 | setSelectedIndex(index); 71 | } 72 | }); 73 | } 74 | 75 | @Override 76 | public void removeAll() { 77 | super.removeAll(); 78 | addTabNewSession(); 79 | } 80 | 81 | public void addTabNewSession() { 82 | String text = "..."; 83 | int location = getTabCount(); 84 | insertTab(text, null, null, null, location); 85 | setTabComponentAt(location, new AddSessionTab(null, text)); 86 | setEnabledAt(location, false); 87 | } 88 | 89 | public class SessionTab extends JPanel { 90 | 91 | private static final long serialVersionUID = 3898047768157638854L; 92 | 93 | public SessionTab(final Component tab, String title, int index) { 94 | FlowLayout flowLayout = new FlowLayout(FlowLayout.CENTER, 3, 3); 95 | setLayout(flowLayout); 96 | JLabel titleLabel = new JLabel(title+" "); 97 | add(titleLabel); 98 | titleLabel.setToolTipText("Rename Session"); 99 | titleLabel.addMouseListener(new MouseAdapter() { 100 | @Override 101 | public void mouseClicked(MouseEvent e) { 102 | setSelectedIndex(index); 103 | if(e.getClickCount() == 2 && canModify()) { 104 | if(renameSessionListener != null) { 105 | renameSessionListener.renameSession(title); 106 | } 107 | } 108 | } 109 | }); 110 | JButton deleteButton = new JButton("X"); 111 | deleteButton.setMargin(new Insets(0, 0, 0, 0)); 112 | deleteButton.setToolTipText("Delete Session"); 113 | deleteButton.addActionListener(new ActionListener() { 114 | 115 | @Override 116 | public void actionPerformed(ActionEvent e) { 117 | if(canModify() && deleteSessionListener != null) { 118 | deleteSessionListener.deleteSession(title); 119 | } 120 | } 121 | }); 122 | add(deleteButton); 123 | 124 | } 125 | } 126 | 127 | public class AddSessionTab extends JPanel { 128 | 129 | private static final long serialVersionUID = 9025776536297919810L; 130 | 131 | public AddSessionTab(final Component tab, String title) { 132 | 133 | setOpaque(false); 134 | FlowLayout flowLayout = new FlowLayout(FlowLayout.CENTER, 3, 3); 135 | setLayout(flowLayout); 136 | JLabel titleLabel = new JLabel(title); 137 | add(titleLabel); 138 | titleLabel.addMouseListener(new MouseAdapter() { 139 | @Override 140 | public void mouseReleased(MouseEvent event) { 141 | JPopupMenu contextMenu = new JPopupMenu(); 142 | JMenuItem newSessionItem = new JMenuItem("Add New Session"); 143 | newSessionItem.addActionListener(new ActionListener() { 144 | 145 | @Override 146 | public void actionPerformed(ActionEvent e) { 147 | if(canModify() && newSessionListener != null) { 148 | newSessionListener.newSession(); 149 | } 150 | } 151 | }); 152 | contextMenu.add(newSessionItem); 153 | JMenuItem cloneSessionItem = new JMenuItem("Clone Selected Session"); 154 | cloneSessionItem.addActionListener(new ActionListener() { 155 | 156 | @Override 157 | public void actionPerformed(ActionEvent e) { 158 | if(canModify() && cloneSessionListener != null) { 159 | cloneSessionListener.cloneSession(); 160 | } 161 | } 162 | }); 163 | contextMenu.add(cloneSessionItem); 164 | contextMenu.show(event.getComponent(), event.getX(), event.getY()); 165 | } 166 | }); 167 | } 168 | } 169 | 170 | public boolean canModify() { 171 | if(!modifEnabled) { 172 | JOptionPane.showMessageDialog(this, "Auth Analyzer running...\nCurrently no modifications possible!\n", "Modification not possible", JOptionPane.WARNING_MESSAGE); 173 | return false; 174 | } 175 | return true; 176 | } 177 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/entities/Token.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.entities; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.net.URLEncoder; 5 | import java.net.URLDecoder; 6 | import java.nio.charset.StandardCharsets; 7 | import java.util.EnumSet; 8 | 9 | import com.protect7.authanalyzer.util.Globals; 10 | 11 | import burp.IHttpRequestResponse; 12 | 13 | public class Token { 14 | 15 | private final String name; 16 | private String value; 17 | private final String extractName; 18 | private final String grepFromString; 19 | private final String grepToString; 20 | private final boolean remove; 21 | private final boolean autoExtract; 22 | private final boolean staticValue; 23 | private final boolean fromToString; 24 | private final boolean promptForInput; 25 | private IHttpRequestResponse requestResponse = null; 26 | private int priority = 0; 27 | private final EnumSet tokenLocationSet; 28 | private final EnumSet autoExtractLocationSet; 29 | private final EnumSet fromToExtractLocationSet; 30 | private final boolean caseSensitiveTokenName; 31 | private final boolean addIfNotExists; 32 | private final boolean urlEncoded; 33 | private boolean urlDecoded; 34 | private String aliases = ""; 35 | 36 | public Token(String name, EnumSet tokenLocationSet, EnumSet autoExtractLocationSet, 37 | EnumSet fromToExtractLocationSet, String value, String extractName, String grepFromString, 38 | String grepToString, boolean remove, boolean autoExtract, boolean staticValue, boolean fromToString, boolean promptForInput, 39 | boolean caseSensitiveTokenName, boolean addIfNotExists, boolean urlEncoded, String test) { 40 | this.name = name; 41 | this.value = value; 42 | this.extractName = extractName; 43 | this.grepFromString = grepFromString; 44 | this.grepToString = grepToString; 45 | this.remove = remove; 46 | this.autoExtract = autoExtract; 47 | this.staticValue = staticValue; 48 | this.fromToString = fromToString; 49 | this.promptForInput = promptForInput; 50 | this.tokenLocationSet = tokenLocationSet; 51 | this.autoExtractLocationSet = autoExtractLocationSet; 52 | this.fromToExtractLocationSet = fromToExtractLocationSet; 53 | this.caseSensitiveTokenName = caseSensitiveTokenName; 54 | this.addIfNotExists = addIfNotExists; 55 | this.urlEncoded = urlEncoded; 56 | } 57 | 58 | public Token(TokenBuilder builder) { 59 | this.name = builder.getName(); 60 | this.value = builder.getValue(); 61 | this.extractName = builder.getExtractName(); 62 | this.grepFromString = builder.getGrepFromString(); 63 | this.grepToString = builder.getGrepToString(); 64 | this.remove = builder.isRemove(); 65 | this.autoExtract = builder.isAutoExtract(); 66 | this.staticValue = builder.isStaticValue(); 67 | this.fromToString = builder.isFromToString(); 68 | this.promptForInput = builder.isPromptForInput(); 69 | this.tokenLocationSet = builder.getTokenLocationSet(); 70 | this.autoExtractLocationSet = builder.getAutoExtractLocationSet(); 71 | this.fromToExtractLocationSet = builder.getFromToExtractLocationSet(); 72 | this.caseSensitiveTokenName = builder.isCaseSensitiveTokenName(); 73 | this.addIfNotExists = builder.isAddIfNotExists(); 74 | this.urlEncoded = builder.isUrlEncoded(); 75 | this.urlDecoded = builder.isUrlDecoded(); 76 | this.aliases = builder.getAliases(); 77 | } 78 | 79 | public String getName() { 80 | return name; 81 | } 82 | public String getUrlEncodedName() { 83 | try { 84 | return URLEncoder.encode(name, StandardCharsets.UTF_8.toString()); 85 | } catch (UnsupportedEncodingException e) { 86 | e.printStackTrace(); 87 | } 88 | return name; 89 | } 90 | public String getValue() { 91 | if(urlEncoded && value != null) { 92 | try { 93 | return URLEncoder.encode(value, StandardCharsets.UTF_8.toString()); 94 | } catch (UnsupportedEncodingException e) { 95 | e.printStackTrace(); 96 | } 97 | } 98 | if(urlDecoded && value != null) { 99 | try { 100 | return URLDecoder.decode(value, StandardCharsets.UTF_8.toString()); 101 | } catch (UnsupportedEncodingException e) { 102 | e.printStackTrace(); 103 | } 104 | } 105 | return value; 106 | } 107 | public void setValue(String value) { 108 | this.value = value; 109 | } 110 | public String getAliases() { 111 | return aliases; 112 | } 113 | public String getExtractName() { 114 | return extractName; 115 | } 116 | public String getGrepFromString() { 117 | return grepFromString; 118 | } 119 | public String getGrepToString() { 120 | return grepToString; 121 | } 122 | public boolean isRemove() { 123 | return remove; 124 | } 125 | public boolean isAutoExtract() { 126 | return autoExtract; 127 | } 128 | public boolean isStaticValue() { 129 | return staticValue; 130 | } 131 | public boolean isFromToString() { 132 | return fromToString; 133 | } 134 | public boolean isPromptForInput() { 135 | return this.promptForInput; 136 | } 137 | public String getHeaderInsertionPointName() { 138 | return Globals.INSERTION_POINT_IDENTIFIER + name + Globals.INSERTION_POINT_IDENTIFIER; 139 | } 140 | public boolean doReplaceAtLocation(TokenLocation tokenLocation) { 141 | return getTokenLocationSet().contains(tokenLocation); 142 | } 143 | 144 | public boolean doAutoExtractAtLocation(AutoExtractLocation autoExtractLocation) { 145 | return getAutoExtractLocationSet().contains(autoExtractLocation); 146 | } 147 | 148 | public boolean doFromToExtractAtLocation(FromToExtractLocation fromToExtractLocation) { 149 | return getFromToExtractLocationSet().contains(fromToExtractLocation); 150 | } 151 | public EnumSet getAutoExtractLocationSet() { 152 | return autoExtractLocationSet; 153 | } 154 | 155 | public EnumSet getTokenLocationSet() { 156 | return tokenLocationSet; 157 | } 158 | 159 | public EnumSet getFromToExtractLocationSet() { 160 | return fromToExtractLocationSet; 161 | } 162 | 163 | public boolean isCaseSensitiveTokenName() { 164 | return caseSensitiveTokenName; 165 | } 166 | 167 | public boolean isAddIfNotExists() { 168 | return addIfNotExists; 169 | } 170 | 171 | public IHttpRequestResponse getRequestResponse() { 172 | return requestResponse; 173 | } 174 | 175 | public void setRequestResponse(IHttpRequestResponse requestResponse) { 176 | this.requestResponse = requestResponse; 177 | } 178 | 179 | public int getPriority() { 180 | return priority; 181 | } 182 | 183 | public void setPriority(int priority) { 184 | this.priority = priority; 185 | } 186 | public String sortString() { 187 | return "" + autoExtract + staticValue + fromToString + promptForInput + name; 188 | } 189 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/util/CurrentConfig.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.ThreadPoolExecutor; 6 | import com.protect7.authanalyzer.controller.RequestController; 7 | import com.protect7.authanalyzer.entities.Session; 8 | import com.protect7.authanalyzer.entities.Token; 9 | import com.protect7.authanalyzer.filter.RequestFilter; 10 | import com.protect7.authanalyzer.gui.util.RequestTableModel; 11 | 12 | import burp.BurpExtender; 13 | import burp.IHttpRequestResponse; 14 | 15 | public class CurrentConfig { 16 | 17 | private static CurrentConfig mInstance = new CurrentConfig(); 18 | //private final String[] patternsStatic = {"token", "code", "user", "mail", "pass", "key", "csrf", "xsrf"}; 19 | //private final String[] patternsDynamic = {"viewstate", "eventvalidation"}; 20 | private final int POOL_SIZE_MIN = 1; 21 | private final RequestController requestController = new RequestController(); 22 | private ThreadPoolExecutor analyzerThreadExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(POOL_SIZE_MIN); 23 | private ArrayList requestFilterList = new ArrayList<>(); 24 | private ArrayList sessions = new ArrayList<>(); 25 | private RequestTableModel tableModel = null; 26 | private boolean running = false; 27 | private boolean dropOriginal = false; 28 | private volatile int mapId = 0; 29 | private boolean respectResponseCodeForSameStatus = true; 30 | private boolean respectResponseCodeForSimilarStatus = true; 31 | private int deviationForSimilarStatus = 5; 32 | private long delayBetweenRequestsInMilliseconds = 0; 33 | 34 | private CurrentConfig() { 35 | } 36 | 37 | public void performAuthAnalyzerRequest(IHttpRequestResponse messageInfo) { 38 | analyzerThreadExecutor.execute(new Runnable() { 39 | @Override 40 | public void run() { 41 | BurpExtender.mainPanel.getCenterPanel().updateAmountOfPendingRequests( 42 | analyzerThreadExecutor.getQueue().size()); 43 | getRequestController().analyze(messageInfo); 44 | try { 45 | Thread.sleep(delayBetweenRequestsInMilliseconds); 46 | } catch (InterruptedException e) { 47 | e.printStackTrace(); 48 | } 49 | } 50 | }); 51 | BurpExtender.mainPanel.getCenterPanel().updateAmountOfPendingRequests( 52 | analyzerThreadExecutor.getQueue().size()); 53 | } 54 | 55 | public static CurrentConfig getCurrentConfig(){ 56 | return mInstance; 57 | } 58 | 59 | public void addRequestFilter(RequestFilter requestFilter) { 60 | getRequestFilterList().add(requestFilter); 61 | } 62 | 63 | public boolean isRunning() { 64 | return running; 65 | } 66 | 67 | public void setRunning(boolean running) { 68 | if(running) { 69 | respectResponseCodeForSameStatus = Setting.getValueAsBoolean(Setting.Item.STATUS_SAME_RESPONSE_CODE); 70 | respectResponseCodeForSimilarStatus = Setting.getValueAsBoolean(Setting.Item.STATUS_SIMILAR_RESPONSE_CODE); 71 | deviationForSimilarStatus = Setting.getValueAsInteger(Setting.Item.STATUS_SIMILAR_RESPONSE_LENGTH); 72 | delayBetweenRequestsInMilliseconds = Setting.getValueAsInteger(Setting.Item.DELAY_BETWEEN_REQUESTS); 73 | if(hasPromptForInput() && Setting.getValueAsBoolean(Setting.Item.ONLY_ONE_THREAD_IF_PROMT_FOR_INPUT)) { 74 | //Set POOL Size to 1 --> if prompt for input dialog appears no further requests will be repeated until dialog is closed 75 | analyzerThreadExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(POOL_SIZE_MIN); 76 | } 77 | else { 78 | int numberOfThreads = Setting.getValueAsInteger(Setting.Item.NUMBER_OF_THREADS); 79 | analyzerThreadExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(numberOfThreads); 80 | } 81 | } 82 | else { 83 | analyzerThreadExecutor.shutdownNow(); 84 | BurpExtender.mainPanel.getCenterPanel().updateAmountOfPendingRequests(0); 85 | } 86 | this.running = running; 87 | } 88 | 89 | private boolean hasPromptForInput() { 90 | for(Session session : sessions) { 91 | for(Token token : session.getTokens()) { 92 | if(token.isPromptForInput()) { 93 | return true; 94 | } 95 | } 96 | } 97 | return false; 98 | } 99 | 100 | public ArrayList getRequestFilterList() { 101 | return requestFilterList; 102 | } 103 | 104 | public RequestFilter getRequestFilterAt(int index) { 105 | return requestFilterList.get(index); 106 | } 107 | 108 | public ArrayList getSessions() { 109 | return sessions; 110 | } 111 | 112 | public void addSession(Session session) { 113 | sessions.add(session); 114 | } 115 | 116 | public void clearSessionList() { 117 | sessions.clear(); 118 | } 119 | 120 | public int getNextMapId() { 121 | mapId++; 122 | return mapId; 123 | } 124 | 125 | public void setDropOriginal(boolean dropOriginal) { 126 | this.dropOriginal = dropOriginal; 127 | } 128 | 129 | public boolean isDropOriginal() { 130 | return dropOriginal; 131 | } 132 | 133 | //Returns session with corresponding name. Returns null if session not exists 134 | public Session getSessionByName(String name) { 135 | for(Session session : sessions) { 136 | if(session.getName().equals(name)) { 137 | return session; 138 | } 139 | } 140 | return null; 141 | } 142 | 143 | public RequestTableModel getTableModel() { 144 | return tableModel; 145 | } 146 | 147 | public void setTableModel(RequestTableModel tableModel) { 148 | this.tableModel = tableModel; 149 | } 150 | 151 | public void clearSessionRequestMaps() { 152 | for(Session session : getSessions()) { 153 | session.clearRequestResponseMap(); 154 | } 155 | } 156 | 157 | public ThreadPoolExecutor getAnalyzerThreadExecutor() { 158 | return analyzerThreadExecutor; 159 | } 160 | 161 | public RequestController getRequestController() { 162 | return requestController; 163 | } 164 | 165 | public boolean isRespectResponseCodeForSameStatus() { 166 | return respectResponseCodeForSameStatus; 167 | } 168 | 169 | public void setRespectResponseCodeForSameStatus(boolean respectResponseCodeForSameStatus) { 170 | this.respectResponseCodeForSameStatus = respectResponseCodeForSameStatus; 171 | } 172 | 173 | public boolean isRespectResponseCodeForSimilarStatus() { 174 | return respectResponseCodeForSimilarStatus; 175 | } 176 | 177 | public void setRespectResponseCodeForSimilarFlag(boolean respectResponseCodeForSimilarStatus) { 178 | this.respectResponseCodeForSimilarStatus = respectResponseCodeForSimilarStatus; 179 | } 180 | 181 | public int getDerivationForSimilarStatus() { 182 | return deviationForSimilarStatus; 183 | } 184 | 185 | public void setDerivationForSimilarStatus(int derivationForSimilarStatus) { 186 | this.deviationForSimilarStatus = derivationForSimilarStatus; 187 | } 188 | } -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/util/RequestTableModel.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.EnumSet; 5 | import javax.swing.SwingUtilities; 6 | import javax.swing.table.AbstractTableModel; 7 | import com.protect7.authanalyzer.entities.OriginalRequestResponse; 8 | import com.protect7.authanalyzer.util.BypassConstants; 9 | import com.protect7.authanalyzer.util.CurrentConfig; 10 | 11 | public class RequestTableModel extends AbstractTableModel { 12 | 13 | private static final long serialVersionUID = 1L; 14 | private final ArrayList originalRequestResponseList = new ArrayList(); 15 | private final CurrentConfig config = CurrentConfig.getCurrentConfig(); 16 | private final int STATIC_COLUMN_COUNT = 7; 17 | 18 | public ArrayList getOriginalRequestResponseList() { 19 | return originalRequestResponseList; 20 | } 21 | 22 | public synchronized void addNewRequestResponse(OriginalRequestResponse requestResponse) { 23 | originalRequestResponseList.add(requestResponse); 24 | final int index = originalRequestResponseList.size()-1; 25 | SwingUtilities.invokeLater(new Runnable() { 26 | 27 | @Override 28 | public void run() { 29 | fireTableRowsInserted(index, index); 30 | } 31 | }); 32 | } 33 | 34 | public boolean isDuplicate(int id, String endpoint) { 35 | for(OriginalRequestResponse requestResponse : originalRequestResponseList) { 36 | if(requestResponse.getEndpoint().equals(endpoint) && requestResponse.getId() < id) { 37 | return true; 38 | } 39 | } 40 | return false; 41 | } 42 | 43 | public void deleteRequestResponse(OriginalRequestResponse requestResponse) { 44 | originalRequestResponseList.remove(requestResponse); 45 | SwingUtilities.invokeLater(new Runnable() { 46 | @Override 47 | public void run() { 48 | fireTableDataChanged(); 49 | } 50 | }); 51 | } 52 | 53 | public void clearRequestMap() { 54 | originalRequestResponseList.clear(); 55 | fireTableDataChanged(); 56 | } 57 | 58 | public OriginalRequestResponse getOriginalRequestResponse(int listIndex) { 59 | if(listIndex < originalRequestResponseList.size()) { 60 | return originalRequestResponseList.get(listIndex); 61 | } 62 | else { 63 | return null; 64 | } 65 | } 66 | 67 | public OriginalRequestResponse getOriginalRequestResponseById(int id) { 68 | for(OriginalRequestResponse requestResponse : originalRequestResponseList) { 69 | if(requestResponse.getId() == id) { 70 | return requestResponse; 71 | } 72 | } 73 | return null; 74 | } 75 | 76 | @Override 77 | public int getColumnCount() { 78 | return STATIC_COLUMN_COUNT + (config.getSessions().size()*4); 79 | } 80 | 81 | @Override 82 | public int getRowCount() { 83 | return originalRequestResponseList.size(); 84 | } 85 | 86 | @Override 87 | public Object getValueAt(int row, int column) { 88 | if(row >= originalRequestResponseList.size()) { 89 | return null; 90 | } 91 | OriginalRequestResponse originalRequestResponse = originalRequestResponseList.get(row); 92 | int tempColunmIndex = 4; 93 | if(column == 0) { 94 | return originalRequestResponse.getId(); 95 | } 96 | if(column == 1) { 97 | return originalRequestResponse.getMethod(); 98 | } 99 | if(column == 2) { 100 | return originalRequestResponse.getHost(); 101 | } 102 | if(column == 3) { 103 | return originalRequestResponse.getUrl(); 104 | } 105 | if(column == 4) { 106 | return originalRequestResponse.getStatusCode(); 107 | } 108 | for(int i=0; i getColumnClass(int columnIndex) { 200 | int tempColunmIndex = 4; 201 | if(columnIndex == 0) { 202 | return Integer.class; 203 | } 204 | if(columnIndex == 1) { 205 | return String.class; 206 | } 207 | if(columnIndex == 2) { 208 | return String.class; 209 | } 210 | if(columnIndex == 3) { 211 | return String.class; 212 | } 213 | if(columnIndex == 4) { 214 | return Integer.class; 215 | } 216 | for(int i=0; i getDefaultSet() { 255 | return EnumSet.of(ID, Method, Host, Path, Status); 256 | } 257 | 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/dialog/TokenSettingsDialog.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.dialog; 2 | 3 | import java.util.ArrayList; 4 | import javax.swing.BoxLayout; 5 | import javax.swing.JCheckBox; 6 | import javax.swing.JLabel; 7 | import javax.swing.JOptionPane; 8 | import javax.swing.JPanel; 9 | import javax.swing.JSeparator; 10 | import javax.swing.JTextField; 11 | import javax.swing.event.DocumentListener; 12 | import javax.swing.event.DocumentEvent; 13 | 14 | import com.protect7.authanalyzer.entities.AutoExtractLocation; 15 | import com.protect7.authanalyzer.entities.FromToExtractLocation; 16 | import com.protect7.authanalyzer.entities.TokenLocation; 17 | import com.protect7.authanalyzer.gui.entity.TokenPanel; 18 | 19 | public class TokenSettingsDialog { 20 | 21 | public TokenSettingsDialog(TokenPanel tokenPanel) { 22 | JTextField aliases = null; 23 | JPanel inputPanel = new JPanel(); 24 | inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.PAGE_AXIS)); 25 | JPanel extractPanel = new JPanel(); 26 | extractPanel.setLayout(new BoxLayout(extractPanel , BoxLayout.PAGE_AXIS)); 27 | JLabel generalSettingsText = new JLabel("General Settings"); 28 | generalSettingsText.putClientProperty("html.disable", null); 29 | inputPanel.add(generalSettingsText); 30 | 31 | JCheckBox removeTokenCheckBox = new JCheckBox("Remove Parameter"); 32 | removeTokenCheckBox.setSelected(tokenPanel.isRemoveToken()); 33 | inputPanel.add(removeTokenCheckBox); 34 | JLabel infoLabel; 35 | if(removeTokenCheckBox.isSelected()) { 36 | infoLabel = new JLabel("Remove Parameter at"); 37 | } 38 | else { 39 | infoLabel = new JLabel("Replace Parameter at"); 40 | } 41 | JCheckBox addParameterCheckBox = new JCheckBox("Add Parameter if not Exists"); 42 | addParameterCheckBox.setSelected(tokenPanel.isAddTokenIfNotExists()); 43 | addParameterCheckBox.setEnabled(!removeTokenCheckBox.isSelected()); 44 | if(addParameterCheckBox.isSelected()) { 45 | infoLabel.setText("Replace / Add Parameter at"); 46 | } 47 | else { 48 | infoLabel.setText("Replace Parameter at"); 49 | } 50 | addParameterCheckBox.addActionListener(e -> { 51 | if(addParameterCheckBox.isSelected()) { 52 | tokenPanel.setAddTokenIfNotExists(true); 53 | removeTokenCheckBox.setEnabled(false); 54 | infoLabel.setText("Replace / Add Parameter at"); 55 | } 56 | else { 57 | tokenPanel.setAddTokenIfNotExists(false); 58 | removeTokenCheckBox.setEnabled(true); 59 | infoLabel.setText("Replace Parameter at"); 60 | } 61 | }); 62 | inputPanel.add(addParameterCheckBox); 63 | 64 | JCheckBox urlEncodeTokenValue = new JCheckBox("URL Encode Value"); 65 | urlEncodeTokenValue.setSelected(tokenPanel.isUrlEncoded()); 66 | urlEncodeTokenValue.setEnabled(!removeTokenCheckBox.isSelected()); 67 | urlEncodeTokenValue.addActionListener(e -> { 68 | tokenPanel.setUrlEncoded(urlEncodeTokenValue.isSelected()); 69 | }); 70 | inputPanel.add(urlEncodeTokenValue); 71 | 72 | // URL Decode Value 73 | JCheckBox urlDecodeTokenValue = new JCheckBox("URL Decode Value"); 74 | urlDecodeTokenValue.setSelected(tokenPanel.isUrlDecoded()); 75 | urlDecodeTokenValue.setEnabled(!removeTokenCheckBox.isSelected()); 76 | urlDecodeTokenValue.addActionListener(e -> { 77 | tokenPanel.setUrlDecoded(urlDecodeTokenValue.isSelected()); 78 | }); 79 | inputPanel.add(urlDecodeTokenValue); 80 | 81 | JCheckBox caseSensitiveTokenNameCheckBox = new JCheckBox("Case Sensitive Parameter Name"); 82 | caseSensitiveTokenNameCheckBox.setSelected(tokenPanel.isCaseSensitiveTokenName()); 83 | caseSensitiveTokenNameCheckBox.addActionListener(e -> { 84 | tokenPanel.setCaseSensitiveTokenName(caseSensitiveTokenNameCheckBox.isSelected()); 85 | }); 86 | inputPanel.add(caseSensitiveTokenNameCheckBox); 87 | 88 | inputPanel.add(new JLabel(" ")); 89 | inputPanel.add(new JSeparator(JSeparator.HORIZONTAL)); 90 | inputPanel.add(new JLabel(" ")); 91 | infoLabel.putClientProperty("html.disable", null); 92 | inputPanel.add(infoLabel); 93 | for(TokenLocation tokenLocation : TokenLocation.values()) { 94 | JCheckBox locationCheckBox = new JCheckBox(tokenLocation.getName()); 95 | locationCheckBox.setSelected(tokenPanel.getTokenLocationSet().contains(tokenLocation)); 96 | locationCheckBox.addActionListener(e -> { 97 | if(locationCheckBox.isSelected()) { 98 | tokenPanel.getTokenLocationSet().add(tokenLocation); 99 | } 100 | else { 101 | tokenPanel.getTokenLocationSet().remove(tokenLocation); 102 | } 103 | }); 104 | inputPanel.add(locationCheckBox); 105 | } 106 | inputPanel.add(extractPanel); 107 | 108 | // add parameter aliases 109 | inputPanel.add(new JLabel(" ")); 110 | inputPanel.add(new JSeparator(JSeparator.HORIZONTAL)); 111 | inputPanel.add(new JLabel(" ")); 112 | JLabel paramAliases = new JLabel("Parameter Aliases (Comma seperated)"); 113 | paramAliases.putClientProperty("html.disable", null); 114 | inputPanel.add(paramAliases); 115 | aliases = new JTextField(tokenPanel.getAliases(),16); 116 | inputPanel.add(aliases); 117 | 118 | removeTokenCheckBox.addActionListener(e -> { 119 | tokenPanel.setFieldsEnabledDisabled(); 120 | tokenPanel.setIsRemoveToken(removeTokenCheckBox.isSelected()); 121 | setChildComponentsEnabled(extractPanel, !removeTokenCheckBox.isSelected()); 122 | if(removeTokenCheckBox.isSelected()) { 123 | infoLabel.setText("Remove Parameter at"); 124 | addParameterCheckBox.setEnabled(false); 125 | urlEncodeTokenValue.setEnabled(false); 126 | } 127 | else { 128 | infoLabel.setText("Replace Parameter at"); 129 | addParameterCheckBox.setEnabled(true); 130 | urlEncodeTokenValue.setEnabled(true); 131 | } 132 | }); 133 | 134 | if(tokenPanel.isSelectedItem(tokenPanel.OPTION_FROM_TO_STRING) || tokenPanel.isSelectedItem(tokenPanel.OPTION_AUTO_EXTRACT)) { 135 | extractPanel.add(new JLabel(" ")); 136 | extractPanel.add(new JSeparator(JSeparator.HORIZONTAL)); 137 | extractPanel.add(new JLabel(" ")); 138 | JLabel tryToExtractValueFromLabel = new JLabel("Try to extract value from"); 139 | tryToExtractValueFromLabel.putClientProperty("html.disable", null); 140 | extractPanel.add(tryToExtractValueFromLabel); 141 | if(tokenPanel.isSelectedItem(tokenPanel.OPTION_AUTO_EXTRACT)) { 142 | for(AutoExtractLocation autoExtractLocation : AutoExtractLocation.values()) { 143 | JCheckBox locationCheckBox = new JCheckBox(autoExtractLocation.getName()); 144 | locationCheckBox.setSelected(tokenPanel.getAutoExtractLocationSet().contains(autoExtractLocation)); 145 | locationCheckBox.addActionListener(e -> { 146 | if(locationCheckBox.isSelected()) { 147 | tokenPanel.getAutoExtractLocationSet().add(autoExtractLocation); 148 | } 149 | else { 150 | tokenPanel.getAutoExtractLocationSet().remove(autoExtractLocation); 151 | } 152 | }); 153 | extractPanel.add(locationCheckBox); 154 | } 155 | 156 | } 157 | if(tokenPanel.isSelectedItem(tokenPanel.OPTION_FROM_TO_STRING)) { 158 | final ArrayList locationCheckBoxList = new ArrayList(); 159 | for(FromToExtractLocation fromToExtractLocation : FromToExtractLocation.values()) { 160 | JCheckBox locationCheckBox = new JCheckBox(fromToExtractLocation.getName()); 161 | locationCheckBox.setSelected(tokenPanel.getFromToExtractLocationSet().contains(fromToExtractLocation)); 162 | if(fromToExtractLocation == FromToExtractLocation.ALL) { 163 | locationCheckBox.addActionListener(e -> { 164 | if(locationCheckBox.isSelected()) { 165 | tokenPanel.getFromToExtractLocationSet().add(fromToExtractLocation); 166 | for(JCheckBox checkBox :locationCheckBoxList) { 167 | checkBox.setEnabled(false); 168 | } 169 | } 170 | else { 171 | tokenPanel.getFromToExtractLocationSet().remove(fromToExtractLocation); 172 | for(JCheckBox checkBox :locationCheckBoxList) { 173 | checkBox.setEnabled(true); 174 | } 175 | } 176 | }); 177 | } 178 | else { 179 | if(fromToExtractLocation != FromToExtractLocation.HEADER && fromToExtractLocation != FromToExtractLocation.BODY) { 180 | locationCheckBoxList.add(locationCheckBox); 181 | locationCheckBox.setEnabled(!tokenPanel.getFromToExtractLocationSet().contains(FromToExtractLocation.ALL)); 182 | } 183 | locationCheckBox.addActionListener(e -> { 184 | if(locationCheckBox.isSelected()) { 185 | tokenPanel.getFromToExtractLocationSet().add(fromToExtractLocation); 186 | } 187 | else { 188 | tokenPanel.getFromToExtractLocationSet().remove(fromToExtractLocation); 189 | } 190 | }); 191 | } 192 | extractPanel.add(locationCheckBox); 193 | } 194 | } 195 | } 196 | setChildComponentsEnabled(extractPanel, !removeTokenCheckBox.isSelected()); 197 | JOptionPane.showConfirmDialog(tokenPanel, inputPanel, "Parameter Settings for " + tokenPanel.getTokenName(), JOptionPane.CLOSED_OPTION); 198 | 199 | // update Aliases on JOptionPane close 200 | tokenPanel.setAliases(aliases.getText()); 201 | } 202 | 203 | private void setChildComponentsEnabled(JPanel parent, boolean enabled) { 204 | for(int i=0; i modifiedHeaders = RequestModifHelper.getModifiedHeaders(modifiedRequestInfo.getHeaders(), session); 79 | byte[] message = BurpExtender.callbacks.getHelpers().buildHttpMessage(modifiedHeaders, modifiedMessageBody); 80 | 81 | // Perform modified request 82 | IHttpRequestResponse sessionRequestResponse = BurpExtender.callbacks 83 | .makeHttpRequest(originalRequestResponse.getHttpService(), message); 84 | 85 | // Analyze Response of modified Request 86 | if (sessionRequestResponse.getRequest() != null && sessionRequestResponse.getResponse() != null) { 87 | IResponseInfo sessionResponseInfo = BurpExtender.callbacks.getHelpers() 88 | .analyzeResponse(sessionRequestResponse.getResponse()); 89 | // Extract Token Values if applicable 90 | for (Token token : session.getTokens()) { 91 | boolean success = false; 92 | if (token.isAutoExtract()) { 93 | success = ExtractionHelper.extractCurrentTokenValue(sessionRequestResponse.getResponse(), sessionResponseInfo, token); 94 | } 95 | if (token.isFromToString()) { 96 | success = ExtractionHelper.extractTokenWithFromToString(sessionRequestResponse.getResponse(), sessionResponseInfo, token); 97 | } 98 | if(success) { 99 | session.getStatusPanel().updateTokenStatus(token); 100 | // Token value successfully extracted. Set TokenRequestResponse for renew feature. 101 | if(token.getRequestResponse() == null || token.getPriority() <= tokenPriority.getPriority()) { 102 | token.setRequestResponse(sessionRequestResponse); 103 | token.setPriority(tokenPriority.getPriority()); 104 | } 105 | } 106 | } 107 | if(originalRequestResponse.getResponse() != null) { 108 | BypassConstants bypassConstant = analyzeResponse(originalRequestResponse.getResponse(), 109 | sessionRequestResponse.getResponse(), originalResponseInfo, sessionResponseInfo); 110 | AnalyzerRequestResponse analyzerRequestResponse = new AnalyzerRequestResponse( 111 | sessionRequestResponse, bypassConstant, null, sessionResponseInfo.getStatusCode(), 112 | sessionRequestResponse.getResponse().length - sessionResponseInfo.getBodyOffset()); 113 | session.putRequestResponse(mapId, analyzerRequestResponse); 114 | } 115 | else { 116 | AnalyzerRequestResponse analyzerRequestResponse = new AnalyzerRequestResponse( 117 | sessionRequestResponse, BypassConstants.NA, null, sessionResponseInfo.getStatusCode(), 118 | sessionRequestResponse.getResponse().length - sessionResponseInfo.getBodyOffset()); 119 | session.putRequestResponse(mapId, analyzerRequestResponse); 120 | } 121 | } else { 122 | AnalyzerRequestResponse analyzerRequestResponse = new AnalyzerRequestResponse( 123 | null, BypassConstants.NA, "Session Request / Response is null. Probably no response " 124 | + "received from server.", -1, -1); 125 | session.putRequestResponse(mapId, analyzerRequestResponse); 126 | } 127 | } 128 | } 129 | String url = ""; 130 | if(originalRequestInfo.getUrl().getQuery() == null) { 131 | url = originalRequestInfo.getUrl().getPath(); 132 | } 133 | else { 134 | url = originalRequestInfo.getUrl().getPath() + "?" + originalRequestInfo.getUrl().getQuery(); 135 | } 136 | String infoText = null; 137 | if(originalRequestResponse.getResponse() == null) { 138 | infoText = "Request Dropped. No Response to show."; 139 | } 140 | int originalStatusCode = -1; 141 | int originalResponseContentLength = -1; 142 | if(originalResponseInfo != null) { 143 | originalStatusCode = originalResponseInfo.getStatusCode(); 144 | originalResponseContentLength = originalRequestResponse.getResponse().length - originalResponseInfo.getBodyOffset(); 145 | } 146 | OriginalRequestResponse requestResponse = new OriginalRequestResponse(mapId, originalRequestResponse, 147 | originalRequestInfo.getMethod(), url, infoText, originalStatusCode, originalResponseContentLength); 148 | CurrentConfig.getCurrentConfig().getTableModel().addNewRequestResponse(requestResponse); 149 | GenericHelper.animateBurpExtensionTab(); 150 | } 151 | } 152 | 153 | private boolean scopeMatches(URL url, Session session) { 154 | URL scopeUrl = session.getScopeUrl(); 155 | if(scopeUrl != null) { 156 | if(url.getHost().equals(scopeUrl.getHost()) && url.getProtocol().equals(scopeUrl.getProtocol()) && 157 | (url.getPath().equals(scopeUrl.getPath()) || scopeUrl.getPath().equals("") || scopeUrl.getPath().equals("/"))) { 158 | return true; 159 | } 160 | } 161 | return false; 162 | } 163 | 164 | public boolean isSameHeader(List headers, Session session) { 165 | String[] headersToReplace = session.getHeadersToReplace().split("\n"); 166 | for (String headerToReplace : headersToReplace) { 167 | if (!headers.contains(headerToReplace)) { 168 | return false; 169 | } 170 | } 171 | return true; 172 | } 173 | 174 | 175 | /* 176 | * Bypass if: - Both Responses have same Response Body and Status Code 177 | * 178 | * Potential Bypass if: - Both Responses have same Response Code - Both 179 | * Responses have +-5% of response body length 180 | * 181 | */ 182 | public BypassConstants analyzeResponse(byte[] originalResponse, byte[] sessionResponse, 183 | IResponseInfo originalResponseInfo, IResponseInfo sessionResponseInfo) { 184 | byte[] originalResponseBody = Arrays.copyOfRange(originalResponse, originalResponseInfo.getBodyOffset(), 185 | originalResponse.length); 186 | byte[] sessionResponseBody = Arrays.copyOfRange(sessionResponse, sessionResponseInfo.getBodyOffset(), 187 | sessionResponse.length); 188 | if (Arrays.equals(originalResponseBody, sessionResponseBody) 189 | && (originalResponseInfo.getStatusCode() == sessionResponseInfo.getStatusCode() || !CurrentConfig.getCurrentConfig().isRespectResponseCodeForSameStatus())) { 190 | return BypassConstants.SAME; 191 | } 192 | if (originalResponseInfo.getStatusCode() == sessionResponseInfo.getStatusCode() || !CurrentConfig.getCurrentConfig().isRespectResponseCodeForSimilarStatus()) { 193 | int range = originalResponseBody.length / (100/CurrentConfig.getCurrentConfig().getDerivationForSimilarStatus()); 194 | int difference = originalResponseBody.length - sessionResponseBody.length; 195 | // Check if difference is in range 196 | if (difference <= range && difference >= -range) { 197 | return BypassConstants.SIMILAR; 198 | } 199 | } 200 | return BypassConstants.DIFFERENT; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/entity/StatusPanel.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.entity; 2 | 3 | import java.awt.Color; 4 | import java.awt.GridBagConstraints; 5 | import java.awt.GridBagLayout; 6 | import java.awt.Insets; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | import java.util.HashMap; 10 | import javax.swing.ImageIcon; 11 | import javax.swing.JButton; 12 | import javax.swing.JLabel; 13 | import javax.swing.JPanel; 14 | import com.protect7.authanalyzer.entities.MatchAndReplace; 15 | import com.protect7.authanalyzer.entities.Session; 16 | import com.protect7.authanalyzer.entities.Token; 17 | import com.protect7.authanalyzer.util.CurrentConfig; 18 | import com.protect7.authanalyzer.util.GenericHelper; 19 | 20 | public class StatusPanel extends JPanel{ 21 | 22 | private final JLabel headerLabel = new JLabel("Header(s) to Replace"); 23 | private final JLabel headerToReplaceValue = new JLabel(""); 24 | private final JLabel headerRemoveLabel = new JLabel("Header(s) to Remove"); 25 | private final JLabel headerToRemoveValue = new JLabel(""); 26 | private final JLabel amountOfFilteredRequestsLabel = new JLabel(""); 27 | private final String SESSION_STARTED_TEXT = " Session Running"; 28 | private final String SESSION_PAUSED_TEXT = " Session Paused"; 29 | private boolean running = true; 30 | private final HashMap tokenLabelMap = new HashMap(); 31 | private final HashMap refreshButtonMap = new HashMap(); 32 | private final HashMap eraseButtonMap = new HashMap(); 33 | private int amountOfFilteredRequests = 0; 34 | private final ImageIcon refreshIcon = new ImageIcon(this.getClass().getClassLoader().getResource("refresh.png")); 35 | private final ImageIcon eraseIcon = new ImageIcon(this.getClass().getClassLoader().getResource("erase.png")); 36 | 37 | private static final long serialVersionUID = -4518448060103739997L; 38 | 39 | public void init(Session session) { 40 | removeAll(); 41 | amountOfFilteredRequests = 0; 42 | setLayout(new GridBagLayout()); 43 | GridBagConstraints c = new GridBagConstraints(); 44 | c.gridy = 0; 45 | c.gridx = 0; 46 | c.anchor = GridBagConstraints.WEST; 47 | c.insets = new Insets(10, 0, 0, 0); 48 | headerLabel.putClientProperty("html.disable", null); 49 | add(headerLabel, c); 50 | 51 | c.gridx = 1; 52 | c.anchor = GridBagConstraints.NORTH; 53 | amountOfFilteredRequestsLabel.setText(""); 54 | add(amountOfFilteredRequestsLabel, c); 55 | 56 | c.gridwidth = 2; 57 | c.gridx = 2; 58 | c.anchor = GridBagConstraints.WEST; 59 | JButton onOffSwitch = new JButton(SESSION_STARTED_TEXT); 60 | onOffSwitch.putClientProperty("html.disable", null); 61 | if(!running) { 62 | onOffSwitch.setText(SESSION_PAUSED_TEXT); 63 | } 64 | onOffSwitch.addActionListener(e -> { 65 | if(running) { 66 | onOffSwitch.setText(SESSION_PAUSED_TEXT); 67 | running = false; 68 | } 69 | else { 70 | onOffSwitch.setText(SESSION_STARTED_TEXT); 71 | running = true; 72 | } 73 | }); 74 | add(onOffSwitch, c); 75 | 76 | c.gridwidth = 4; 77 | c.gridx = 0; 78 | c.gridy++; 79 | c.insets = new Insets(5, 0, 0, 0); 80 | headerToReplaceValue.putClientProperty("html.disable", null); 81 | add(headerToReplaceValue, c); 82 | if(session.getHeadersToReplace().equals("")) { 83 | headerLabel.setText(" ");//Set ugly placeholder to keep match and replace distance 84 | headerToReplaceValue.setVisible(false); 85 | } 86 | else { 87 | headerToReplaceValue.setText(format(session.getHeadersToReplace(), session)); 88 | headerLabel.setText("

Header(s) to Replace"); 89 | headerLabel.putClientProperty("html.disable", null); 90 | headerToReplaceValue.setVisible(true); 91 | } 92 | 93 | if(session.isRemoveHeaders()) { 94 | c.gridy++; 95 | c.insets = new Insets(10, 0, 0, 0); 96 | headerRemoveLabel.putClientProperty("html.disable", null); 97 | add(headerRemoveLabel, c); 98 | c.insets = new Insets(5, 0, 0, 0); 99 | c.gridy++; 100 | headerToRemoveValue.putClientProperty("html.disable", null); 101 | add(headerToRemoveValue, c); 102 | if(session.getHeadersToRemove().equals("")) { 103 | headerToRemoveValue.setText("No Headers specified"); 104 | } 105 | else { 106 | headerToRemoveValue.setText(format(session.getHeadersToRemove(), session)); 107 | } 108 | } 109 | 110 | c.insets = new Insets(10, 0, 0, 0); 111 | c.gridy++; 112 | c.fill = GridBagConstraints.HORIZONTAL; 113 | if(session.getTokens().size() == 0) { 114 | JLabel dummyLabel = new JLabel("

 

"); 115 | dummyLabel.putClientProperty("html.disable", null); 116 | c.gridwidth = 2; 117 | c.gridx = 0; 118 | add(dummyLabel, c); 119 | } 120 | for(Token token : session.getTokens()) { 121 | c.gridwidth = 2; 122 | c.gridx = 0; 123 | c.anchor = GridBagConstraints.WEST; 124 | JLabel tokenLabel = new JLabel(getTokenText(token)); 125 | tokenLabel.putClientProperty("html.disable", null); 126 | tokenLabelMap.put(token.getName(), tokenLabel); 127 | add(tokenLabel, c); 128 | if(token.isAutoExtract() || token.isFromToString()) { 129 | c.gridx = 2; 130 | c.gridwidth = 1; 131 | c.fill = GridBagConstraints.NONE; 132 | JButton renewButton = new JButton(refreshIcon); 133 | renewButton.setToolTipText("Refresh Value"); 134 | refreshButtonMap.put(token.getName(), renewButton); 135 | if(token.getRequestResponse() == null) { 136 | renewButton.setEnabled(false); 137 | } 138 | renewButton.addActionListener(e -> { 139 | if(token.getRequestResponse() != null) { 140 | CurrentConfig.getCurrentConfig().performAuthAnalyzerRequest(token.getRequestResponse()); 141 | } 142 | }); 143 | add(renewButton, c); 144 | JButton eraseButton = new JButton(eraseIcon); 145 | eraseButton.setToolTipText("Erase Value"); 146 | eraseButtonMap.put(token.getName(), eraseButton); 147 | if(token.getValue() == null) { 148 | eraseButton.setEnabled(false); 149 | } 150 | eraseButton.addActionListener(e -> { 151 | token.setValue(null); 152 | updateTokenStatus(token); 153 | }); 154 | c.insets = new Insets(10, 10, 0, 0); 155 | c.gridx = 3; 156 | add(eraseButton, c); 157 | c.insets = new Insets(10, 0, 0, 0); 158 | } 159 | c.gridy++; 160 | } 161 | if(session.getMatchAndReplaceList().size() > 0) { 162 | c.gridwidth = 2; 163 | c.gridx = 0; 164 | JLabel matchLabel = new JLabel("Match:"); 165 | matchLabel.putClientProperty("html.disable", null); 166 | add(matchLabel, c); 167 | c.gridx = 1; 168 | JLabel replaceLabel = new JLabel("Replace:"); 169 | replaceLabel.putClientProperty("html.disable", null); 170 | add(replaceLabel, c); 171 | c.gridy++; 172 | c.insets = new Insets(5, 0, 0, 0); 173 | } 174 | for(MatchAndReplace matchAndReplace : session.getMatchAndReplaceList()) { 175 | c.gridx = 0; 176 | add(new JLabel(formatMatchAndReplaceText(matchAndReplace.getMatch())), c); 177 | c.gridx = 1; 178 | add(new JLabel(formatMatchAndReplaceText(matchAndReplace.getReplace())), c); 179 | c.gridy++; 180 | } 181 | } 182 | 183 | private String getTokenText(Token token) { 184 | String tokenInfo = ""; 185 | if(token.isAutoExtract()) { 186 | tokenInfo = "Auto Extract Value"; 187 | } 188 | if(token.isStaticValue()) { 189 | tokenInfo = "Static Value"; 190 | } 191 | if(token.isFromToString()) { 192 | tokenInfo = "Extract value from[" + token.getGrepFromString().replace("<", "<") + 193 | "] to [" + token.getGrepToString().replace("<", "<") + "]"; 194 | } 195 | if(token.isPromptForInput()) { 196 | tokenInfo = "Prompt for Input"; 197 | } 198 | if(token.isRemove()) { 199 | tokenInfo = "Remove Parameter"; 200 | } 201 | if(token.isAutoExtract() || token.isFromToString()) { 202 | if(token.getValue() != null) { 203 | SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); 204 | String timestap = sdf.format(new Date()); 205 | tokenInfo += " - Last extracted at " + timestap; 206 | } 207 | } 208 | String tokenValue = "Value: null"; 209 | if(token.getValue() != null) { 210 | String value; 211 | if(token.getValue().length() > 80) { 212 | value = token.getValue().substring(0, 80) + "..."; 213 | } 214 | else { 215 | value = token.getValue(); 216 | } 217 | if(token.isFromToString() || token.isAutoExtract()) { 218 | tokenValue = "Value: " + value.replace("<", "<") + ""; 219 | } 220 | else { 221 | tokenValue = "Value: " + value.replace("<", "<") + ""; 222 | } 223 | } 224 | if(token.isRemove()) { 225 | tokenValue = "Value: [Remove Parameter]"; 226 | } 227 | return "

" + token.getName().replace("<", "<").replace("\n", "
") + 228 | "
("+tokenInfo+")

" + tokenValue.replace("\n", "
") + "

"; 229 | } 230 | 231 | private String format(String text, Session session) { 232 | String htmlString = "

"; 233 | for(String line : text.split("\n")) { 234 | int maxLength = 100; 235 | if(line.length() > maxLength) { 236 | htmlString += line.substring(0, maxLength) + "..."; 237 | } 238 | else { 239 | htmlString += line; 240 | } 241 | htmlString += "
"; 242 | } 243 | htmlString += "

"; 244 | //String htmlString = "

"+text.replace("<", "<").replace("\n", "
")+"

"; 245 | return htmlString; 246 | } 247 | 248 | private String formatMatchAndReplaceText(String text) { 249 | if(text.length() > 18) { 250 | return text.substring(0, 15) + "..."; 251 | } 252 | return text; 253 | } 254 | 255 | public boolean isRunning() { 256 | return running; 257 | } 258 | 259 | public void incrementAmountOfFitleredRequests() { 260 | amountOfFilteredRequests++; 261 | amountOfFilteredRequestsLabel.setText("Amount of Filtered Requests: " + amountOfFilteredRequests); 262 | GenericHelper.uiUpdateAnimation(amountOfFilteredRequestsLabel, Color.RED); 263 | } 264 | 265 | public void updateTokenStatus(Token token) { 266 | JLabel tokenLabel = tokenLabelMap.get(token.getName()); 267 | tokenLabel.putClientProperty("html.disable", null); 268 | tokenLabel.setText(getTokenText(token)); 269 | GenericHelper.uiUpdateAnimation(tokenLabel, new Color(0, 153, 0)); 270 | if(token.getValue() != null) { 271 | if(refreshButtonMap.get(token.getName()) != null) { 272 | refreshButtonMap.get(token.getName()).setEnabled(true); 273 | } 274 | if(eraseButtonMap.get(token.getName()) != null) { 275 | eraseButtonMap.get(token.getName()).setEnabled(true); 276 | } 277 | } 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/gui/dialog/RepeatRequestFilterDialog.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.gui.dialog; 2 | 3 | import java.awt.Component; 4 | import java.awt.Dimension; 5 | import java.awt.GridBagConstraints; 6 | import java.awt.GridBagLayout; 7 | import java.awt.Insets; 8 | import java.awt.event.ActionEvent; 9 | import java.awt.event.ActionListener; 10 | import java.awt.event.FocusEvent; 11 | import java.awt.event.FocusListener; 12 | import java.util.ArrayList; 13 | import java.util.HashSet; 14 | import javax.swing.Box; 15 | import javax.swing.JButton; 16 | import javax.swing.JDialog; 17 | import javax.swing.JLabel; 18 | import javax.swing.JPanel; 19 | import javax.swing.WindowConstants; 20 | import javax.swing.border.EmptyBorder; 21 | import com.protect7.authanalyzer.gui.main.ConfigurationPanel; 22 | import com.protect7.authanalyzer.gui.util.HintCheckBox; 23 | import com.protect7.authanalyzer.gui.util.PlaceholderTextField; 24 | import com.protect7.authanalyzer.util.GenericHelper; 25 | import burp.BurpExtender; 26 | import burp.IHttpRequestResponse; 27 | import burp.IRequestInfo; 28 | import burp.IResponseInfo; 29 | 30 | public class RepeatRequestFilterDialog extends JDialog { 31 | 32 | private static final long serialVersionUID = -5771536154913129631L; 33 | private String patternText = ""; 34 | private String methodsText = ""; 35 | 36 | public RepeatRequestFilterDialog(Component parent, ConfigurationPanel configurationPanel, 37 | IHttpRequestResponse[] selectedMessages) { 38 | JPanel inputPanel = (JPanel) getContentPane(); 39 | inputPanel.setLayout(new GridBagLayout()); 40 | inputPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); 41 | GridBagConstraints c = new GridBagConstraints(); 42 | c.fill = GridBagConstraints.HORIZONTAL; 43 | c.insets = new Insets(0, 5, 10, 0); 44 | c.gridx = 0; 45 | c.gridy = 0; 46 | c.gridwidth = 1; 47 | 48 | HintCheckBox uniqueRequestsCheckbox = new HintCheckBox("Filter Duplicates", 49 | "Duplicated Requests only repeated once. Unique identifier: METHOD + HOST + URL + PATH"); 50 | inputPanel.add(uniqueRequestsCheckbox, c); 51 | inputPanel.add(Box.createRigidArea(new Dimension(0, 10))); 52 | 53 | HintCheckBox withResponseCheckbox = new HintCheckBox("With avalibale Responses", 54 | "The request will no be repeated ff the selected Message does not has a response."); 55 | c.gridy++; 56 | inputPanel.add(withResponseCheckbox, c); 57 | inputPanel.add(Box.createRigidArea(new Dimension(0, 10))); 58 | 59 | JLabel patternLabel = new JLabel("With specified Pattern:"); 60 | c.insets = new Insets(0, 5, 5, 0); 61 | c.gridy++; 62 | inputPanel.add(patternLabel, c); 63 | PlaceholderTextField patternTextField = new PlaceholderTextField(); 64 | patternTextField.setPlaceholder("Leave empty to apply no filter..."); 65 | c.gridy++; 66 | c.insets = new Insets(0, 5, 20, 0); 67 | inputPanel.add(patternTextField, c); 68 | inputPanel.add(Box.createRigidArea(new Dimension(0, 10))); 69 | 70 | JLabel methodLabel = new JLabel("HTTP Method(s) (Comma seperated):"); 71 | c.insets = new Insets(0, 5, 5, 0); 72 | c.gridy++; 73 | inputPanel.add(methodLabel, c); 74 | PlaceholderTextField methodTextField = new PlaceholderTextField(25); 75 | methodTextField.setPlaceholder("Leave empty to apply no filter..."); 76 | c.insets = new Insets(0, 5, 20, 0); 77 | c.gridy++; 78 | inputPanel.add(methodTextField, c); 79 | inputPanel.add(Box.createRigidArea(new Dimension(0, 20))); 80 | 81 | JLabel contentTypeLabel = new JLabel("Response Content Type(s) (Comma seperated):"); 82 | c.insets = new Insets(0, 5, 5, 0); 83 | c.gridy++; 84 | inputPanel.add(contentTypeLabel, c); 85 | PlaceholderTextField contentTypeTextField = new PlaceholderTextField(25); 86 | contentTypeTextField.setPlaceholder("(HTML, JSON) Leave empty to apply no filter..."); 87 | c.insets = new Insets(0, 5, 20, 0); 88 | c.gridy++; 89 | inputPanel.add(contentTypeTextField, c); 90 | inputPanel.add(Box.createRigidArea(new Dimension(0, 20))); 91 | 92 | JButton repeatButton = new JButton("Repeat Requests (" + selectedMessages.length + ")"); 93 | c.gridy++; 94 | inputPanel.add(repeatButton, c); 95 | 96 | repeatButton.addActionListener(new ActionListener() { 97 | 98 | @Override 99 | public void actionPerformed(ActionEvent e) { 100 | IHttpRequestResponse[] messages = getMessageToRepeat(selectedMessages, 101 | uniqueRequestsCheckbox.isSelected(), withResponseCheckbox.isSelected(), 102 | patternTextField.getText().trim(), methodTextField.getText(), contentTypeTextField.getText()); 103 | GenericHelper.repeatRequests(messages, configurationPanel); 104 | dispose(); 105 | } 106 | }); 107 | 108 | uniqueRequestsCheckbox.addActionListener(e2 -> updateRepeatButtonText(repeatButton, selectedMessages, 109 | uniqueRequestsCheckbox.isSelected(), withResponseCheckbox.isSelected(), 110 | patternTextField.getText().trim(), methodTextField.getText(), contentTypeTextField.getText())); 111 | withResponseCheckbox.addActionListener(e2 -> updateRepeatButtonText(repeatButton, selectedMessages, 112 | uniqueRequestsCheckbox.isSelected(), withResponseCheckbox.isSelected(), 113 | patternTextField.getText().trim(), methodTextField.getText(), contentTypeTextField.getText())); 114 | patternTextField.addFocusListener(new FocusListener() { 115 | 116 | @Override 117 | public void focusLost(FocusEvent e) { 118 | if (textChanged(patternTextField.getText(), methodTextField.getText())) { 119 | updateRepeatButtonText(repeatButton, selectedMessages, uniqueRequestsCheckbox.isSelected(), 120 | withResponseCheckbox.isSelected(), patternTextField.getText().trim(), 121 | methodTextField.getText(), contentTypeTextField.getText()); 122 | } 123 | } 124 | 125 | @Override 126 | public void focusGained(FocusEvent e) { 127 | } 128 | }); 129 | patternTextField.addActionListener(e2 -> updateRepeatButtonText(repeatButton, selectedMessages, 130 | uniqueRequestsCheckbox.isSelected(), withResponseCheckbox.isSelected(), 131 | patternTextField.getText().trim(), methodTextField.getText(), contentTypeTextField.getText())); 132 | methodTextField.addFocusListener(new FocusListener() { 133 | 134 | @Override 135 | public void focusLost(FocusEvent e) { 136 | if (textChanged(patternTextField.getText(), methodTextField.getText())) { 137 | updateRepeatButtonText(repeatButton, selectedMessages, uniqueRequestsCheckbox.isSelected(), 138 | withResponseCheckbox.isSelected(), patternTextField.getText().trim(), 139 | methodTextField.getText(), contentTypeTextField.getText()); 140 | } 141 | } 142 | 143 | @Override 144 | public void focusGained(FocusEvent e) { 145 | } 146 | }); 147 | methodTextField.addActionListener(e2 -> updateRepeatButtonText(repeatButton, selectedMessages, 148 | uniqueRequestsCheckbox.isSelected(), withResponseCheckbox.isSelected(), 149 | patternTextField.getText().trim(), methodTextField.getText(), contentTypeTextField.getText())); 150 | 151 | contentTypeTextField.addFocusListener(new FocusListener() { 152 | 153 | @Override 154 | public void focusLost(FocusEvent e) { 155 | if (textChanged(patternTextField.getText(), methodTextField.getText())) { 156 | updateRepeatButtonText(repeatButton, selectedMessages, uniqueRequestsCheckbox.isSelected(), 157 | withResponseCheckbox.isSelected(), patternTextField.getText().trim(), 158 | methodTextField.getText(), contentTypeTextField.getText()); 159 | } 160 | } 161 | 162 | @Override 163 | public void focusGained(FocusEvent e) { 164 | } 165 | }); 166 | contentTypeTextField.addActionListener(e2 -> updateRepeatButtonText(repeatButton, selectedMessages, 167 | uniqueRequestsCheckbox.isSelected(), withResponseCheckbox.isSelected(), 168 | patternTextField.getText().trim(), methodTextField.getText(), contentTypeTextField.getText())); 169 | 170 | setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 171 | setVisible(true); 172 | setTitle("Repeat Filter Options"); 173 | pack(); 174 | setLocationRelativeTo(parent); 175 | } 176 | 177 | private boolean textChanged(String currentPatternText, String currentMethodsText) { 178 | if (currentPatternText.equals(patternText) && currentMethodsText.equals(methodsText)) { 179 | return false; 180 | } else { 181 | patternText = currentPatternText; 182 | methodsText = currentMethodsText; 183 | return true; 184 | } 185 | } 186 | 187 | private void updateRepeatButtonText(JButton repeatButton, IHttpRequestResponse[] sourceMessages, boolean onlyUnique, 188 | boolean onlyWithResponse, String pattern, String methods, String responseCodentTypes) { 189 | int length = getMessageToRepeat(sourceMessages, onlyUnique, onlyWithResponse, pattern, methods, 190 | responseCodentTypes).length; 191 | repeatButton.setText("Repeat Requests (" + length + ")"); 192 | } 193 | 194 | private IHttpRequestResponse[] getMessageToRepeat(IHttpRequestResponse[] sourceMessages, boolean onlyUnique, 195 | boolean onlyWithResponse, String pattern, String methods, String responseConentTypes) { 196 | ArrayList messages = new ArrayList<>(); 197 | HashSet uniqueRequests = new HashSet(); 198 | for (IHttpRequestResponse message : sourceMessages) { 199 | boolean doRepeat = true; 200 | if (onlyWithResponse && message.getResponse() == null) { 201 | doRepeat = false; 202 | } 203 | if (doRepeat && onlyUnique) { 204 | String key = message.getHttpService().getHost(); 205 | if (message.getRequest() != null) { 206 | IRequestInfo requestInfo = BurpExtender.callbacks.getHelpers().analyzeRequest(message); 207 | key += requestInfo.getMethod() + requestInfo.getUrl().getPath(); 208 | } 209 | if (uniqueRequests.contains(key)) { 210 | doRepeat = false; 211 | } else { 212 | uniqueRequests.add(key); 213 | } 214 | } 215 | if (doRepeat && (!pattern.equals("") || !methods.equals(""))) { 216 | if (message.getRequest() != null) { 217 | String request = new String(message.getRequest()); 218 | if (!pattern.equals("")) { 219 | if (!request.contains(pattern)) { 220 | doRepeat = false; 221 | } 222 | } 223 | if (!methods.equals("")) { 224 | String[] methodSplit = methods.split(","); 225 | boolean methodInList = false; 226 | for (String method : methodSplit) { 227 | if (request.startsWith(method.trim())) { 228 | methodInList = true; 229 | break; 230 | } 231 | } 232 | if (!methodInList) { 233 | doRepeat = false; 234 | } 235 | } 236 | } 237 | } 238 | if (doRepeat && !responseConentTypes.equals("")) { 239 | if(message.getResponse() == null) { 240 | doRepeat = false; 241 | } 242 | else { 243 | IResponseInfo responseInfo = BurpExtender.callbacks.getHelpers().analyzeResponse(message.getResponse()); 244 | String stateMimeType = responseInfo.getStatedMimeType(); 245 | String[] contentTypeSplit = responseConentTypes.split(","); 246 | boolean contentTypeInList = false; 247 | for (String contentType : contentTypeSplit) { 248 | if (stateMimeType.toLowerCase().equals(contentType.trim().toLowerCase())) { 249 | contentTypeInList = true; 250 | break; 251 | } 252 | } 253 | if (!contentTypeInList) { 254 | doRepeat = false; 255 | } 256 | } 257 | } 258 | if (doRepeat) { 259 | messages.add(message); 260 | } 261 | } 262 | return messages.toArray(new IHttpRequestResponse[messages.size()]); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/util/DataExporter.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.util; 2 | 3 | import java.io.File; 4 | import java.io.FileWriter; 5 | import java.io.IOException; 6 | import java.util.ArrayList; 7 | import java.util.Base64; 8 | import java.util.EnumSet; 9 | import com.protect7.authanalyzer.entities.AnalyzerRequestResponse; 10 | import com.protect7.authanalyzer.entities.OriginalRequestResponse; 11 | import com.protect7.authanalyzer.entities.Session; 12 | import burp.BurpExtender; 13 | import burp.IHttpRequestResponse; 14 | import burp.IRequestInfo; 15 | import burp.IResponseInfo; 16 | 17 | public class DataExporter { 18 | 19 | private static DataExporter mInstance = new DataExporter(); 20 | 21 | public static synchronized DataExporter getDataExporter() { 22 | return mInstance; 23 | } 24 | 25 | public boolean createXML(File file, ArrayList originalRequestResponseList, 26 | ArrayList sessions, EnumSet mainColumns, EnumSet sessionColumns, 27 | boolean doBase64Encode) { 28 | try { 29 | FileWriter writer = new FileWriter(file); 30 | writer.write(""); 31 | 32 | // Write Body 33 | for (OriginalRequestResponse requestResponse : originalRequestResponseList) { 34 | writer.write(""); 35 | IHttpRequestResponse originalRequestResponse = requestResponse.getRequestResponse(); 36 | StringBuffer row = new StringBuffer(); 37 | IRequestInfo originalRequestInfo = BurpExtender.callbacks.getHelpers() 38 | .analyzeRequest(originalRequestResponse); 39 | for (MainColumn column : mainColumns) { 40 | row.append("<" 41 | + column.getName().replace(" ", "_") + ">" + setIntoCDATA(getCellValue(column, 42 | requestResponse.getId(), originalRequestInfo, originalRequestResponse, requestResponse.getComment())) 43 | + "\n"); 44 | } 45 | for (SessionColumn column : sessionColumns) { 46 | if (column != SessionColumn.BYPASS_STATUS) { 47 | String data; 48 | if ((column == SessionColumn.REQUEST || column == SessionColumn.RESPONSE) && doBase64Encode) { 49 | data = Base64.getEncoder().encodeToString(getCellValue(column, requestResponse.getId(), 50 | originalRequestResponse, null).getBytes()); 51 | } else { 52 | data = setIntoCDATA(getCellValue(column, requestResponse.getId(), 53 | originalRequestResponse, null)); 54 | } 55 | row.append("" + data + "\n"); 57 | } 58 | } 59 | for (Session session : sessions) { 60 | AnalyzerRequestResponse sessionRequestResponse = session.getRequestResponseMap() 61 | .get(requestResponse.getId()); 62 | for (SessionColumn column : sessionColumns) { 63 | String data; 64 | if ((column == SessionColumn.REQUEST || column == SessionColumn.RESPONSE) && doBase64Encode) { 65 | data = Base64.getEncoder() 66 | .encodeToString(setIntoCDATA(getCellValue(column, requestResponse.getId(), 67 | sessionRequestResponse.getRequestResponse(), 68 | sessionRequestResponse.getStatus())).getBytes()); 69 | } else { 70 | data = setIntoCDATA(getCellValue(column, requestResponse.getId(), 71 | sessionRequestResponse.getRequestResponse(), sessionRequestResponse.getStatus())); 72 | } 73 | row.append("<" + session.getName().replace(" ", "_") + "_" + column.getName().replace(" ", "_") 74 | + ">" + data + "\n"); 76 | } 77 | } 78 | row.deleteCharAt(row.length() - 1); 79 | writer.write(row.toString()); 80 | writer.write("\n"); 81 | } 82 | writer.write(""); 83 | writer.close(); 84 | } catch (IOException e) { 85 | BurpExtender.callbacks.printError("Error. Can not write data to XML file. " + e.getMessage()); 86 | return false; 87 | } 88 | return true; 89 | } 90 | 91 | public boolean createHTML(File file, ArrayList originalRequestResponseList, 92 | ArrayList sessions, EnumSet mainColumns, EnumSet sessionColumns) { 93 | try { 94 | FileWriter writer = new FileWriter(file); 95 | writer.write(""); 100 | // Write Title 101 | StringBuffer titleRow = new StringBuffer(); 102 | for (MainColumn column : mainColumns) { 103 | titleRow.append(""); 104 | } 105 | for (SessionColumn column : sessionColumns) { 106 | if (column != SessionColumn.BYPASS_STATUS) { 107 | titleRow.append(""); 108 | } 109 | } 110 | for (Session session : sessions) { 111 | for (SessionColumn column : sessionColumns) { 112 | titleRow.append(""); 113 | } 114 | } 115 | titleRow.deleteCharAt(titleRow.length() - 1); 116 | writer.write(titleRow.toString()); 117 | writer.write("\n"); 118 | 119 | // Write Body 120 | for (OriginalRequestResponse requestResponse : originalRequestResponseList) { 121 | writer.write(""); 122 | IHttpRequestResponse originalRequestResponse = requestResponse.getRequestResponse(); 123 | StringBuffer row = new StringBuffer(); 124 | IRequestInfo originalRequestInfo = null; 125 | if(originalRequestResponse != null) { 126 | originalRequestInfo = BurpExtender.callbacks.getHelpers().analyzeRequest(originalRequestResponse); 127 | } 128 | for (MainColumn column : mainColumns) { 129 | row.append(""); 132 | } 133 | for (SessionColumn column : sessionColumns) { 134 | if (column != SessionColumn.BYPASS_STATUS) { 135 | row.append(""); 137 | } 138 | } 139 | for (Session session : sessions) { 140 | AnalyzerRequestResponse sessionRequestResponse = session.getRequestResponseMap() 141 | .get(requestResponse.getId()); 142 | for (SessionColumn column : sessionColumns) { 143 | String startTag = ""; 148 | if(column == SessionColumn.BYPASS_STATUS) { 149 | if(cellValue.equals(BypassConstants.SAME.getName())) { 150 | startTag = "\n"); 165 | } 166 | writer.write("
" + encodeHTML(column.getName()) + "" + encodeHTML("Original " + column.getName()) + "" + encodeHTML(session.getName() + " " + column.getName()) + "
" + encodeHTML( 130 | getCellValue(column, requestResponse.getId(), originalRequestInfo, originalRequestResponse, requestResponse.getComment())) 131 | + "
" + encodeHTML(getCellValue(column, requestResponse.getId(), 136 | originalRequestResponse, null)) + "
" ; 144 | String cellValue = getCellValue(column, requestResponse.getId(), 145 | sessionRequestResponse.getRequestResponse(), 146 | sessionRequestResponse.getStatus()); 147 | String endTag = "
" ; 151 | } 152 | if(cellValue.equals(BypassConstants.SIMILAR.getName())) { 153 | startTag = "
" ; 154 | } 155 | if(cellValue.equals(BypassConstants.DIFFERENT.getName())) { 156 | startTag = "
" ; 157 | } 158 | } 159 | row.append(startTag + encodeHTML(cellValue) + endTag); 160 | } 161 | } 162 | row.deleteCharAt(row.length() - 1); 163 | writer.write(row.toString()); 164 | writer.write("

Generated by "+ Globals.EXTENSION_NAME +" Version " + Globals.VERSION + ""); 167 | writer.close(); 168 | } catch (IOException e) { 169 | BurpExtender.callbacks.printError("Error. Can not write data to HTML file. " + e.getMessage()); 170 | return false; 171 | } 172 | return true; 173 | } 174 | 175 | private String encodeHTML(String text) { 176 | return text.replaceAll("<", "<").replace("\n", "
"); 177 | } 178 | 179 | private String setIntoCDATA(String text) { 180 | return "", "]]>"; 181 | } 182 | 183 | private String getCellValue(MainColumn column, Integer id, IRequestInfo requestInfo, 184 | IHttpRequestResponse requestResponse, String comment) { 185 | switch (column) { 186 | case ID: 187 | return String.valueOf(id); 188 | case METHOD: 189 | return requestInfo.getMethod(); 190 | case COMMENT: 191 | return comment; 192 | case HOST: 193 | return requestResponse.getHttpService().getHost(); 194 | case PATH: 195 | if (requestInfo.getUrl().getQuery() == null) { 196 | return requestInfo.getUrl().getPath(); 197 | } else { 198 | return requestInfo.getUrl().getPath() + "?" + requestInfo.getUrl().getQuery(); 199 | } 200 | default: 201 | return null; 202 | } 203 | } 204 | 205 | private String getCellValue(SessionColumn column, Integer id, 206 | IHttpRequestResponse requestResponse, BypassConstants bypassStatus) { 207 | IResponseInfo responseInfo = null; 208 | if(requestResponse != null && requestResponse.getResponse() != null) { 209 | responseInfo = BurpExtender.callbacks.getHelpers() 210 | .analyzeResponse(requestResponse.getResponse()); 211 | } 212 | switch (column) { 213 | case BYPASS_STATUS: 214 | return bypassStatus.getName(); 215 | case REQUEST: 216 | if(requestResponse != null && requestResponse.getRequest() != null) { 217 | return new String(requestResponse.getRequest()); 218 | } 219 | else { 220 | return ""; 221 | } 222 | case RESPONSE: 223 | if(requestResponse != null && requestResponse.getResponse() != null) { 224 | return new String(requestResponse.getResponse()); 225 | } 226 | else { 227 | return ""; 228 | } 229 | case STATUS_CODE: 230 | if(responseInfo != null) { 231 | return String.valueOf(responseInfo.getStatusCode()); 232 | } 233 | else { 234 | return "-1"; 235 | } 236 | case CONTENT_LENGTH: 237 | if(responseInfo != null && requestResponse.getResponse() != null) { 238 | return String.valueOf(requestResponse.getResponse().length - responseInfo.getBodyOffset()); 239 | } 240 | else { 241 | return "-1"; 242 | } 243 | default: 244 | return null; 245 | } 246 | } 247 | 248 | public enum MainColumn { 249 | 250 | ID("ID"), METHOD("Method"), HOST("Host"), PATH("Path"), COMMENT("Comment"); 251 | 252 | private final String name; 253 | 254 | public String getName() { 255 | return this.name; 256 | } 257 | 258 | private MainColumn(String name) { 259 | this.name = name; 260 | } 261 | } 262 | 263 | public enum SessionColumn { 264 | 265 | BYPASS_STATUS("Bypass Status"), STATUS_CODE("Status Code"), CONTENT_LENGTH("Content Length"), 266 | REQUEST("Request"), RESPONSE("Response"); 267 | 268 | private String name; 269 | 270 | // getter method 271 | public String getName() { 272 | return this.name; 273 | } 274 | 275 | private SessionColumn(String name) { 276 | this.name = name; 277 | } 278 | } 279 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Auth Analyzer 2 | ### Table of Contents 3 | - [What is it?](#what-is-it) 4 | - [Why should I use Auth Analyzer?](#why-should-i-use-auth-analyzer) 5 | - [GUI Overview](#gui-overview) 6 | - [Parameter Extraction](#parameter-extraction) 7 | * [Auto Extract](#auto-extract) 8 | * [From To String](#from-to-string) 9 | * [Static Value](#static-value) 10 | * [Prompt for Input](#prompt-for-input) 11 | - [Parameter Replacement](#parameter-replacement) 12 | * [Replacement Location](#replacement-location) 13 | - [Parameter removement](#parameter-removement) 14 | - [Sample Usage](#sample-usage) 15 | * [Auto extract session Cookie](#auto-extract-session-cookie) 16 | * [Session Header and CSRF Token Parameter](#session-header-and-csrf-token-parameter) 17 | * [Auto extract from JavaScript variable](#auto-extract-from-javascript-variable) 18 | * [Auto extract and insert a Bearer Token](#auto-extract-and-insert-a-bearer-token) 19 | * [Test several roles at a time](#test-several-roles-at-a-time) 20 | * [Refresh Auto Exracted Parameter Value](#refresh-auto-exracted-parameter-value) 21 | * [Test idempotent Operations](#test-idempotent-operations) 22 | * [Test anonymous sessions](#test-anonymous-sessions) 23 | * [Test CORS configuration](#test-cors-configuration) 24 | * [Test CSRF Check mechanism](#test-csrf-check-mechanism) 25 | * [Verify the Bypass Status](#verify-the-bypass-status) 26 | - [Processing Filter](#processing-filter) 27 | - [Bypass Detection](#bypass-detection) 28 | - [Features](#features) 29 | 30 | 31 | ## What is it? 32 | The Burp extension helps you to find authorization bugs. Just navigate through the web application with a high privileged user and let the Auth Analyzer repeat your requests for any defined non-privileged user. With the possibility to define Parameters the Auth Analyzer is able to extract and replace parameter values automatically. With this for instance, CSRF tokens or even whole session characteristics can be auto extracted from responses and replaced in further requests. Each response will be analyzed and tagged on its bypass status. 33 | 34 | ## Why should I use Auth Analyzer? 35 | There are other existing Burp Extensions doing basically similar stuff. However, the force of the parameter feature and automatic value extraction is the main reason for choosing Auth Analyzer. With this you don’t have to know the content of the data which must be exchanged. You can easily define your parameters and cookies and Auth Analyzer will catch on the fly the values needed. The Auth Analyzer does not perform any preflight requests. It does basically just the same thing as your web app. With your defined user roles / sessions. 36 | 37 | ## GUI Overview 38 | (1) Create or Clone a Session for every user you want to test. 39 | 40 | (2) Save and load session setup 41 | 42 | (3) Specify the session characteristics (Header(s) and / or Parameter(s) to replace) 43 | 44 | (4) Set Filters if needed 45 | 46 | (5) Start / Stop and Pause Auth Analyzer 47 | 48 | (6) Specify table filter 49 | 50 | (7) Navigate through Web App with another user and track results of the repeated requests 51 | 52 | (8) Export table data to XML or HTML 53 | 54 | (9) Manually analyze original and repeated requests / responses 55 | 56 | 57 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/complete_gui.png) 58 | 59 | ## Semi Automated Authorization Testing 60 | If you have the resources you want to test in your sitemap, it is very easy and quick to perform your authorization tests. In the very first step define your sessions you want to test. Then just expand your sitemap, select the resources and repeat the requests through the context menu. Additionally you can define some options which requests should be repeated and which not. With this you can perform authorization tests of a complex website within seconds. 61 | 62 | ## Parameter Extraction 63 | The Auth Analyzer has the possibility to define parameters which are replaced before the request for the given session will be repeated. The value for the given parameter can be set according to different requirements. 64 | ### Auto Extract 65 | The parameter value will be extracted if it occurs in a response with one of the following constraints: 66 | 67 | * A response with a `Set-Cookie Header` with a Cookie name set to the defined `Extract Field Name` 68 | 69 | * An `HTML Document Response` contains an input field with the name attribute set to the defined `Extract Field Name` 70 | 71 | * A `JSON Response` contains a key set to the `Extract Field Name` 72 | 73 | Per default the Auth Analyzer tries to auto extract the parameter value from all locations. However, clicking on the parameter settings icon lets you restrict the auto extract location according to your needs. 74 | 75 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/param_auto_extract_location.png) 76 | 77 | ### From To String 78 | The parameter will be extracted if the response contains the specified `From String` and `To String` in a line. The From-To String can be set either manually or directly by the corresponding context menu. Just mark the word you want to extract in any response and set as `From-To Extract` for the parameter you like. 79 | 80 | Per default the Auth Analyzer tries to extract the value from header and body at most textual responses. However, clicking on the parameter settings icon lets you restrict the From-To extract location according to your needs. 81 | 82 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/param_fromto_extract_location.png) 83 | 84 | ### Static Value 85 | A static parameter value can be defined. This can be used for instance for static CSRF tokens or login credentials. 86 | 87 | ### Prompt for Input 88 | You will be prompted for input if the defined parameter is present in a request. This can be used for instance to set 2FA codes. 89 | 90 | ## Parameter Replacement 91 | If a value is set (extracted or defined by the user) it will be replaced if the corresponding parameter is present in a request. The conditions for parameter replacements are: 92 | ### Replacement Location 93 | The parameter will be replaced if it is present at one of the following locations: 94 | 95 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/param_replace_locations.png) 96 | 97 | * `In Path` (e.g. `/api/user/99/profile` --> if a parameter named `user` is present, the value `99` will be replaced) 98 | 99 | * `URL Parameter` (e.g. `email=hans.wurst[a]gmail.com`) 100 | 101 | * `Cookie Parameter` (e.g. `PHPSESSID=mb8rkrcdg8765dt91vpum4u21v`) 102 | 103 | * `Body Parameter` either `URL-Encoded` or `Multipart Form Data` 104 | 105 | * `JSON Parameter` (e.g. `{"email":"hans.wurst[a]gmail.com"}`) 106 | 107 | Per default the parameter value will be replaced at each location. However, clicking on the parameter settings icon lets you restrict the location according to your needs. 108 | 109 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/param_replace_location.png) 110 | 111 | 112 | ## Parameter removement 113 | The defined parameter can be removed completely for instance to test CSRF check mechanisms. 114 | 115 | ## Sample Usage 116 | 117 | ### Auto extract session Cookie 118 | Define the username and password as a `static value`. The session cookie name must be defined as `auto extract`. Verify that you start navigating through the application with no session cookie set. Login to the web app. The Auth Analyzer will repeat the login request with the static parameters and automatically gets the session by the `Set-Cookie` header. This Cookie will be used for further requests of the given session. The defined Cookie will be treated as a parameter and therefore no Cookie Header must be defined. 119 | 120 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/auto_extract_session_id_1.png) 121 | 122 | Hint: You can restrict the extract and replace conditions for a parameter to avoid malfunction at the extracting / replacing stage. 123 | 124 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/parameter_settings_session_cookie.png) 125 | 126 | ### Session Header and CSRF Token Parameter 127 | Define a Cookie header and a CSRF token (with `auto value extract`). The CSRF token value will be extracted if it is present in an `HTML Input Tag`, a `Set-Cookie Header` or a `JSON Response` of the given session. 128 | 129 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/session_header_with_csrf_token.png) 130 | 131 | ### Auto extract from JavaScript variable 132 | Since the `Auto Extract` method only works on `HTML Input Fields`, `JSON Objects` or `Set-Cookie Headers` we must use the generic extraction method called `From To String`. With this extraction method we can extract any value from a response if it is located between a unique starting and ending string. The Auth Analyzer provides a context menu method to set the `From String` and `To String` automatically. Just mark the String you want to extract and set as `From-To Extract` by the context menu. 133 | 134 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/auto_extract_csrftoken_from_js_var.png) 135 | 136 | ### Auto extract and insert a Bearer Token 137 | Since the Authorization Header is not treated as a parameter (as it is done with the Cookie Header), we can use a header insertion point to achieve what we want. Just mark and right click the value you want to replace in the specified header. The `defaultvalue` will be used if no parameter value is extracted yet. 138 | 139 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/auto_extract_and_insert_bearer_token.png) 140 | 141 | ### Test several roles at a time 142 | Just create as many sessions as you want to test several roles at a time. 143 | 144 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/several_sessions_1.png) 145 | 146 | ### Refresh Auto Exracted Parameter Value 147 | Just press `Renew` on the session status panel or repeat the affected request by the context menu (mouse right click in the table entry). Hint: The login request(s) can be marked and filtered afterwards. 148 | 149 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/renew_session.png) 150 | 151 | ### Test idempotent Operations 152 | Original Requests can be dropped for testing idempotent operations (e.g. a `DELETE` function). 153 | 154 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/idempotent_operations.png) 155 | 156 | ### Test anonymous sessions 157 | If an anonymous user needs a valid characteristic (e.g., a valid cookie value) you have to define the header as usual. Otherwise, you can define a header to remove as follows: 158 | 159 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/test_anonymous.png) 160 | 161 | ### Test CORS configuration 162 | You can easily test a large number of endpoints on its individual CORS settings by adding an Origin header at `Header(s) to replace` and select `Test CORS` on the Session Panel. By selecting `Test CORS` the Auth Analyzer will change the HTTP method to `OPTIONS` before the request is repeated 163 | 164 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/test_cors.png) 165 | 166 | ### Test CSRF Check mechanism 167 | A specified parameter can be removed by selecting the `Remove Checkbox`. This can be used for instance to test the CSRF check mechanism. 168 | 169 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/remove_csrf.png) 170 | 171 | ### Verify the Bypass Status 172 | The Auth Analyzer provides a build in comparison view to verify the differences between two responses. Just mark the message you want to analyze and change the message view `(1)`. You are now able to compare the two requests `(2) (3)`. The built in `Diff` Feature will calculate and show the differences between the two requests in real time `(4)` 173 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/compare_view.png) 174 | 175 | Expanded Diff view: 176 | 177 | ![Auth Analyzer](https://github.com/simioni87/auth_analyzer/blob/main/pics/diff_view.png) 178 | 179 | ## Processing Filter 180 | The Auth Analyzer should process two types of requests / responses: 181 | 182 | * The response contains a value which must be extracted 183 | 184 | * The requested resource should not be accessible by the defined session(s) 185 | 186 | For instance, we don’t want to process a static JavaScript file because it is accessible for everyone and (hopefully) does not contain any protected data. To achieve this, we can set following types of filters: 187 | * Only In Scope (only requests to the set Scope will be processed) 188 | * Only Proxy Traffic (only requests to the "Proxy History" will be processed) 189 | * Exclude Filetypes (specified Filetypes can be excluded) 190 | * Exclude HTTP Methods (specified HTTP Methods can be excluded) 191 | * Exclude Status Codes (specified Status Codes can be excluded) 192 | * Exclude Paths (specified Paths can be excluded) 193 | * Exclude Queries / Params (specified Queries / Params can be excluded) 194 | 195 | ## Automated Response Analysis 196 | * The Response will be declared as SAME if `Both Responses have same Response Body` and `same Response Code` 197 | * The Response will be declared as SIMILAR if `Both Responses have same Response Code` and `Both Responses have +-5% of response body length` 198 | * The Response will be declared as DIFFERENT in every other case 199 | 200 | ## Features 201 | * Session Creation for each user role 202 | * Renaming and Removing a Session 203 | * Clone a Session 204 | * Set any amount of Headers to replace / add 205 | * Set Headers to remove 206 | * Set any amount of parameters to replace 207 | * Define how the parameter value will be discovered (automatic, static, prompt for input, from to string) 208 | * Remove a specified parameter 209 | * Detailed Filter Rules 210 | * Detailed Status Panel for each Session 211 | * Pause each Session separately 212 | * Renew Auto Extracted Parameter Value automatically 213 | * Repeat Request by context menu 214 | * Table Data Filter 215 | * Table Data Export Functionality 216 | * Start / Stop / Pause the "Auth Analyzer" 217 | * Pause each Session seperatly 218 | * Restrict session to defined scope 219 | * Filter Requests with same header(s) 220 | * Drop Original Request functionality 221 | * Detailed view of all processed Requests and Responses 222 | * Send Header(s) and / or Parameter(s) directly to Auth Analyzer by Context Menu 223 | * Auto save current configuration 224 | * Save to file and load from file current configuration 225 | * Search function in repeated requests 226 | * Semi Automated Authoriztaion Testing 227 | -------------------------------------------------------------------------------- /src/com/protect7/authanalyzer/util/ExtractionHelper.java: -------------------------------------------------------------------------------- 1 | package com.protect7.authanalyzer.util; 2 | 3 | import java.io.StringReader; 4 | import java.io.UnsupportedEncodingException; 5 | import java.net.URLDecoder; 6 | import java.nio.charset.StandardCharsets; 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.Comparator; 10 | import java.util.EnumSet; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | import org.jsoup.Jsoup; 14 | import org.jsoup.nodes.Document; 15 | import org.jsoup.nodes.Element; 16 | import org.jsoup.select.Elements; 17 | import com.google.gson.JsonElement; 18 | import com.google.gson.JsonObject; 19 | import com.google.gson.JsonParser; 20 | import com.google.gson.stream.JsonReader; 21 | import com.protect7.authanalyzer.entities.AutoExtractLocation; 22 | import com.protect7.authanalyzer.entities.FromToExtractLocation; 23 | import com.protect7.authanalyzer.entities.Token; 24 | import com.protect7.authanalyzer.entities.TokenBuilder; 25 | import com.protect7.authanalyzer.entities.TokenLocation; 26 | import burp.BurpExtender; 27 | import burp.ICookie; 28 | import burp.IHttpRequestResponse; 29 | import burp.IParameter; 30 | import burp.IRequestInfo; 31 | import burp.IResponseInfo; 32 | 33 | public class ExtractionHelper { 34 | 35 | public static boolean extractCurrentTokenValue(byte[] sessionResponse, IResponseInfo sessionResponseInfo, Token token) { 36 | if(token.doAutoExtractAtLocation(AutoExtractLocation.COOKIE)) { 37 | for (ICookie cookie : sessionResponseInfo.getCookies()) { 38 | if (cookie.getName().equals(token.getExtractName())) { 39 | token.setValue(cookie.getValue()); 40 | return true; 41 | } 42 | } 43 | } 44 | if (token.doAutoExtractAtLocation(AutoExtractLocation.HTML) && (sessionResponseInfo.getStatedMimeType().equals("HTML") 45 | || sessionResponseInfo.getInferredMimeType().equals("HTML"))) { 46 | try { 47 | String bodyAsString = new String(Arrays.copyOfRange(sessionResponse, 48 | sessionResponseInfo.getBodyOffset(), sessionResponse.length)); 49 | String value = getTokenValueFromInputField(bodyAsString, token.getExtractName()); 50 | if (value != null) { 51 | token.setValue(value); 52 | return true; 53 | } 54 | } catch (Exception e) { 55 | BurpExtender.callbacks.printError("Can not parse HTML Response. Error Message: " + e.getMessage()); 56 | } 57 | } 58 | if (token.doAutoExtractAtLocation(AutoExtractLocation.JSON) && (sessionResponseInfo.getStatedMimeType().equals("JSON") 59 | || sessionResponseInfo.getInferredMimeType().equals("JSON"))) { 60 | JsonElement jsonElement = getBodyAsJson(sessionResponse, sessionResponseInfo); 61 | if(jsonElement != null) { 62 | String value = getJsonTokenValue(jsonElement, token); 63 | if (value != null) { 64 | token.setValue(value); 65 | return true; 66 | } 67 | } 68 | } 69 | return false; 70 | } 71 | 72 | public static String getTokenValueFromInputField(String document, String name) { 73 | Document doc = Jsoup.parse(document); 74 | Elements csrfFields = doc.getElementsByAttributeValue("name", name); 75 | for(Element element : csrfFields) { 76 | String csrfValue = element.attr("value"); 77 | if(csrfValue != null && !csrfValue.equals("")) { 78 | return csrfValue; 79 | } 80 | csrfValue = element.attr("content"); 81 | if(csrfValue != null && !csrfValue.equals("")) { 82 | return csrfValue; 83 | } 84 | } 85 | return null; 86 | } 87 | 88 | public static boolean extractTokenWithFromToString(byte[] sessionResponse, IResponseInfo responseInfo, Token token) { 89 | try { 90 | boolean doExtract = token.doFromToExtractAtLocation(FromToExtractLocation.ALL); 91 | for(FromToExtractLocation locationType : FromToExtractLocation.values()) { 92 | if(locationType != FromToExtractLocation.ALL && locationType != FromToExtractLocation.HEADER && locationType != FromToExtractLocation.BODY) { 93 | if (token.doFromToExtractAtLocation(locationType) && (responseInfo.getStatedMimeType().toUpperCase().equals(locationType.toString()) 94 | || responseInfo.getInferredMimeType().toUpperCase().equals(locationType.toString()))) { 95 | doExtract = true; 96 | break; 97 | } 98 | } 99 | } 100 | //Do extract per default if stated and interfered MIME Type can not be evaluated (e.g. redirect response without body content) 101 | if(responseInfo.getInferredMimeType().equals("") && responseInfo.getStatedMimeType().equals("")) { 102 | doExtract = true; 103 | } 104 | if(doExtract) { 105 | String responseAsString = null; 106 | if(token.doFromToExtractAtLocation(FromToExtractLocation.HEADER) && token.doFromToExtractAtLocation(FromToExtractLocation.BODY)) { 107 | responseAsString = new String(sessionResponse); 108 | } 109 | else if(token.doFromToExtractAtLocation(FromToExtractLocation.HEADER) && !token.doFromToExtractAtLocation(FromToExtractLocation.BODY)) { 110 | responseAsString = new String(Arrays.copyOfRange(sessionResponse, 0, responseInfo.getBodyOffset())); 111 | } 112 | else if(!token.doFromToExtractAtLocation(FromToExtractLocation.HEADER) && token.doFromToExtractAtLocation(FromToExtractLocation.BODY)) { 113 | responseAsString = new String(Arrays.copyOfRange(sessionResponse, responseInfo.getBodyOffset(), sessionResponse.length)); 114 | } 115 | if(responseAsString != null) { 116 | int beginIndex = responseAsString.indexOf(token.getGrepFromString()); 117 | if (beginIndex != -1) { 118 | beginIndex = beginIndex + token.getGrepFromString().length(); 119 | // Only single lines in extraction scope 120 | String lineWithValue = responseAsString.substring(beginIndex).split("\n")[0]; 121 | String value = null; 122 | if (token.getGrepToString().equals("")) { 123 | value = lineWithValue; 124 | } else { 125 | if (lineWithValue.contains(token.getGrepToString())) { 126 | value = lineWithValue.substring(0, lineWithValue.indexOf(token.getGrepToString())); 127 | } 128 | } 129 | if (value != null) { 130 | token.setValue(value); 131 | return true; 132 | } 133 | } 134 | } 135 | } 136 | } catch (Exception e) { 137 | BurpExtender.callbacks.printError("Can not extract from to value. Error Message: " + e.getMessage()); 138 | } 139 | return false; 140 | } 141 | 142 | private static String getJsonTokenValue(JsonElement jsonElement, Token token) { 143 | if (jsonElement.isJsonObject()) { 144 | JsonObject jsonObject = jsonElement.getAsJsonObject(); 145 | for (Map.Entry entry : jsonObject.entrySet()) { 146 | if (entry.getValue().isJsonArray() || entry.getValue().isJsonObject()) { 147 | return getJsonTokenValue(entry.getValue(), token); 148 | } 149 | if (entry.getValue().isJsonPrimitive()) { 150 | if (entry.getKey().equals(token.getExtractName())) { 151 | return entry.getValue().getAsString(); 152 | } 153 | } 154 | } 155 | } 156 | if (jsonElement.isJsonArray()) { 157 | for (JsonElement arrayJsonEl : jsonElement.getAsJsonArray()) { 158 | if (arrayJsonEl.isJsonObject()) { 159 | return getJsonTokenValue(arrayJsonEl.getAsJsonObject(), token); 160 | } 161 | } 162 | } 163 | return null; 164 | } 165 | 166 | private static JsonElement getBodyAsJson(byte[] response, IResponseInfo responseInfo) { 167 | try { 168 | String bodyAsString = new String(Arrays.copyOfRange(response, 169 | responseInfo.getBodyOffset(), response.length)); 170 | JsonReader reader = new JsonReader(new StringReader(bodyAsString)); 171 | reader.setLenient(true); 172 | JsonElement jsonElement = JsonParser.parseReader(reader); 173 | return jsonElement; 174 | } catch (Exception e) { 175 | BurpExtender.callbacks.printError("Can not parse JSON Response. Error Message: " + e.getMessage()); 176 | } 177 | return null; 178 | } 179 | 180 | public static ArrayList extractTokensFromMessages(IHttpRequestResponse[] messages) { 181 | HashMap tokenMap = new HashMap(); 182 | String[] staticPatterns = Setting.getValueAsArray(Setting.Item.AUTOSET_PARAM_STATIC_PATTERNS); 183 | String[] dynamicPatterns = Setting.getValueAsArray(Setting.Item.AUTOSET_PARAM_DYNAMIC_PATTERNS); 184 | for(IHttpRequestResponse message : messages) { 185 | if(message.getRequest() != null) { 186 | IRequestInfo requestInfo = BurpExtender.callbacks.getHelpers().analyzeRequest(message.getRequest()); 187 | for(IParameter param : requestInfo.getParameters()) { 188 | boolean process = false; 189 | boolean isDynamic = false; 190 | for(String pattern : staticPatterns) { 191 | if(param.getName().toLowerCase().contains(pattern)) { 192 | process = true; 193 | break; 194 | } 195 | } 196 | for(String pattern : dynamicPatterns) { 197 | if(param.getName().toLowerCase().contains(pattern)) { 198 | process = true; 199 | isDynamic = true; 200 | break; 201 | } 202 | } 203 | if(process) { 204 | boolean autoExtract = isDynamic; 205 | if(tokenMap.containsKey(param.getName())) { 206 | autoExtract = tokenMap.get(param.getName()).isAutoExtract(); 207 | } 208 | Token token = null; 209 | String urlDecodedName; 210 | try { 211 | urlDecodedName = URLDecoder.decode(param.getName(), StandardCharsets.UTF_8.toString()); 212 | } catch (UnsupportedEncodingException e) { 213 | urlDecodedName = param.getName(); 214 | } 215 | String urlDecodedValue; 216 | try { 217 | urlDecodedValue = URLDecoder.decode(param.getValue(), StandardCharsets.UTF_8.toString()); 218 | } catch (UnsupportedEncodingException e) { 219 | urlDecodedValue = param.getValue(); 220 | } 221 | if(param.getType() == IParameter.PARAM_COOKIE) { 222 | // Create Token with dynamic value 223 | token = new TokenBuilder() 224 | .setName(urlDecodedName) 225 | .setTokenLocationSet(EnumSet.of(TokenLocation.COOKIE)) 226 | .setAutoExtractLocationSet(EnumSet.of(AutoExtractLocation.COOKIE)) 227 | .setValue(param.getValue()) 228 | .setExtractName(param.getName()) 229 | .setIsAutoExtract(true) 230 | .build(); 231 | } 232 | if(param.getType() == IParameter.PARAM_URL) { 233 | // Create Token with static value 234 | token = new TokenBuilder() 235 | .setName(urlDecodedName) 236 | .setTokenLocationSet(EnumSet.of(TokenLocation.URL)) 237 | .setAutoExtractLocationSet(EnumSet.of(AutoExtractLocation.HTML)) 238 | .setValue(urlDecodedValue) 239 | .setExtractName(urlDecodedName) 240 | .setIsAutoExtract(autoExtract) 241 | .setIsStaticValue(!autoExtract) 242 | .build(); 243 | } 244 | if(param.getType() == IParameter.PARAM_BODY) { 245 | // Create Token with static value 246 | token = new TokenBuilder() 247 | .setName(urlDecodedName) 248 | .setTokenLocationSet(EnumSet.of(TokenLocation.BODY)) 249 | .setAutoExtractLocationSet(EnumSet.of(AutoExtractLocation.HTML)) 250 | .setValue(urlDecodedValue) 251 | .setExtractName(urlDecodedName) 252 | .setIsAutoExtract(autoExtract) 253 | .setIsStaticValue(!autoExtract) 254 | .build(); 255 | } 256 | if(param.getType() == IParameter.PARAM_JSON) { 257 | token = new TokenBuilder() 258 | .setName(urlDecodedName) 259 | .setTokenLocationSet(EnumSet.of(TokenLocation.JSON)) 260 | .setAutoExtractLocationSet(EnumSet.of(AutoExtractLocation.JSON)) 261 | .setValue(urlDecodedValue) 262 | .setExtractName(urlDecodedName) 263 | .setIsAutoExtract(autoExtract) 264 | .setIsStaticValue(!autoExtract) 265 | .build(); 266 | } 267 | if(token != null) { 268 | tokenMap.put(token.getName(), token); 269 | } 270 | } 271 | } 272 | } 273 | if(message.getResponse() != null) { 274 | IResponseInfo responseInfo = BurpExtender.callbacks.getHelpers().analyzeResponse(message.getResponse()); 275 | for(ICookie cookie : responseInfo.getCookies()) { 276 | Token token = new TokenBuilder() 277 | .setName(cookie.getName()) 278 | .setTokenLocationSet(EnumSet.of(TokenLocation.COOKIE)) 279 | .setAutoExtractLocationSet(EnumSet.of(AutoExtractLocation.COOKIE)) 280 | .setExtractName(cookie.getName()) 281 | .setIsAutoExtract(true) 282 | .build(); 283 | tokenMap.put(token.getName(), token); 284 | } 285 | if(responseInfo.getStatedMimeType().equals("JSON") || responseInfo.getInferredMimeType().equals("JSON")) { 286 | JsonElement jsonElement = getBodyAsJson(message.getResponse(), responseInfo); 287 | if(jsonElement != null) { 288 | createTokensFromJson(jsonElement, tokenMap); 289 | } 290 | } 291 | } 292 | } 293 | ArrayList tokenList = new ArrayList(tokenMap.values()); 294 | tokenList.sort(Comparator.comparing(Token::sortString)); 295 | return tokenList; 296 | } 297 | 298 | private static void createTokensFromJson(JsonElement jsonElement, HashMap tokenMap) { 299 | if (jsonElement.isJsonObject()) { 300 | JsonObject jsonObject = jsonElement.getAsJsonObject(); 301 | for (Map.Entry entry : jsonObject.entrySet()) { 302 | if (entry.getValue().isJsonArray() || entry.getValue().isJsonObject()) { 303 | createTokensFromJson(jsonElement, tokenMap); 304 | } 305 | if (entry.getValue().isJsonPrimitive()) { 306 | String[] staticPatterns = Setting.getValueAsArray(Setting.Item.AUTOSET_PARAM_STATIC_PATTERNS); 307 | for(String pattern : staticPatterns) { 308 | if(entry.getKey().toLowerCase().contains(pattern)) { 309 | Token token = new TokenBuilder() 310 | .setName(entry.getKey()) 311 | .setTokenLocationSet(EnumSet.of(TokenLocation.JSON)) 312 | .setAutoExtractLocationSet(EnumSet.of(AutoExtractLocation.JSON)) 313 | .setExtractName(entry.getKey()) 314 | .setIsAutoExtract(true) 315 | .build(); 316 | tokenMap.put(token.getName(), token); 317 | break; 318 | } 319 | } 320 | } 321 | } 322 | } 323 | if (jsonElement.isJsonArray()) { 324 | for (JsonElement arrayJsonEl : jsonElement.getAsJsonArray()) { 325 | if (arrayJsonEl.isJsonObject()) { 326 | createTokensFromJson(jsonElement, tokenMap); 327 | } 328 | } 329 | } 330 | } 331 | } 332 | --------------------------------------------------------------------------------