diff --git a/.gitignore b/.gitignore index b63da45..ae5bf1f 100644 --- a/.gitignore +++ b/.gitignore @@ -38,5 +38,8 @@ bin/ ### VS Code ### .vscode/ +### IntelliJ IDEA +.idea/ + ### Mac OS ### .DS_Store \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 39dac47..ae7bd84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,4 +13,9 @@ ## [0.0.3] - 2024-07-30 ### Fixed -- Fixed the issue with action listener on Swig Utils \ No newline at end of file +- Fixed the issue with action listener on Swig Utils + +## [0.0.4] - 2024-08-27 + +### Added +- HTTP/2 to HTTP/1.1 downgrade \ No newline at end of file diff --git a/README.md b/README.md index e247f3a..bfc6f30 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Burp Suite extension that mutates ciphers to bypass TLS-fingerprint based bot de - **Firefox Mode**: Install the following list of cipher suites: 4865, 4867, 4866, 49195, 49199, 52393, 52392, 49196, 49200, 49162, 49161, 49171, 49172, 156, 157, 47, 53 and add the Firefox User-Agent header. - **Chrome Mode**: Use cipher suites 4865, 4866, 4867, 49195, 49199, 49196, 49200, 52393, 52392, 49171, 49172, 156, 157, 47, 53 and add the Chrome User-Agent header. - **Safari Mode**: Include cipher suites 4865, 4866, 4867, 49196, 49195, 52393, 49200, 49199, 52392, 49162, 49161, 49172, 49171, 157, 156, 53, 47, 49160, 49170, 10 and add the Safari User-Agent header. +- **HTTP2 Downgrade**: By default, Burp uses HTTP/2 to communicate with all servers that advertise support for it during the TLS handshake. When that feature is selected, the Burp Suite will use HTTP/1 even if the server supports HTTP/2. It allows to bypass aggressive HTTP/2 fingerprinting. - **Brute Force Mode**: Tries different combinations of TLS protocol versions and cipher suites. For a full list, visit: [PortSwigger/bypass-bot-detection](https://github.com/PortSwigger/bypass-bot-detection/blob/d677ad52a3cad97aa51b39b66976e35490cef76d/src/main/java/net/portswigger/burp/extensions/Constants.java#L88). ## Warning diff --git a/build.gradle b/build.gradle index 0228faa..30c8793 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ plugins { } group = 'net.portswigger.burp.extensions' -version = '0.0.3' +version = '0.0.4' description = 'bypass-bot-detection' repositories { @@ -12,7 +12,7 @@ repositories { } dependencies { - compileOnly 'net.portswigger.burp.extensions:montoya-api:2023.12.1' + implementation 'net.portswigger.burp.extensions:montoya-api:2024.7' implementation 'com.google.code.gson:gson:2.11.0' testImplementation platform('org.junit:junit-bom:5.10.0') diff --git a/src/main/java/net/portswigger/burp/extensions/BypassBotDetection.java b/src/main/java/net/portswigger/burp/extensions/BypassBotDetection.java index f41fcfa..a1354fa 100644 --- a/src/main/java/net/portswigger/burp/extensions/BypassBotDetection.java +++ b/src/main/java/net/portswigger/burp/extensions/BypassBotDetection.java @@ -18,7 +18,8 @@ public void initialize(MontoyaApi montoyaApi) { try { new Utilities(montoyaApi); BlockingQueue tasks = new LinkedBlockingQueue<>(); - ThreadPoolExecutor taskEngine = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, tasks); + int processors = Runtime.getRuntime().availableProcessors(); + ThreadPoolExecutor taskEngine = new ThreadPoolExecutor(processors, processors*2, 1, TimeUnit.MINUTES, tasks); Utilities.saveTLSSettings(); montoyaApi.userInterface().registerContextMenuItemsProvider(new TLSContextMenuItemsProvider(taskEngine)); montoyaApi.logging().logToOutput(Utilities.getResourceString("greetings")); diff --git a/src/main/java/net/portswigger/burp/extensions/Constants.java b/src/main/java/net/portswigger/burp/extensions/Constants.java index c6f3303..f1dc1db 100644 --- a/src/main/java/net/portswigger/burp/extensions/Constants.java +++ b/src/main/java/net/portswigger/burp/extensions/Constants.java @@ -5,18 +5,63 @@ public class Constants { - public static int THREAD_POOL_SIZE = 1; + public static int MAX_ATTEMPTS = 3; public static String BURP_TLS_NEGOTIATION = "use_custom"; public static String MATCH_AND_REPLACE_RULE_TYPE = "request_header"; public static String MATCH_AND_REPLACE_REGEXP = "^User-Agent.*$"; - public static String FIREFOX_UA = "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0"; + public static String[] MATCH_AND_REPLACE_REGEXP_HTTP2 = new String[] { + "^Sec-Ch-Ua:.*$", + "^Sec-Ch-Ua-Mobile:.*$", + "^Sec-Ch-Ua-Platform:.*$", + "^Sec-Fetch-Site:.*$", + "^Sec-Fetch-Mode:.*$", + "^Sec-Fetch-User:.*$", + "^Sec-Fetch-Dest:.*$", +// "^Sec-CH-UA-Arch:.*$", +// "^Sec-CH-UA-Bitness:.*$", +// "^Sec-CH-UA-Model:.*$", +// "^Sec-CH-UA-Platform-Version:.*$", +// "^Sec-CH-UA-Form-Factors:.*$", +// "^Sec-CH-UA-Full-Version-List:.*$", +// "^Sec-CH-UA-WoW64:.*$", +// "^Priority:.*$" + }; + public static String FROZEN_UA = "User-Agent: Mozilla/5.0 (%s) %s"; + + public static Map FIREFOX_PLATFORMS = Map.of( + "Windows", + "Windows NT 10.0; Win64; x64; rv:129.0", + "Mac", + "Macintosh; Intel Mac OS X 14.6; rv:129.0", + "Linux", + "X11; Linux x86_64; rv:129.0"); + public static Map CHROME_PLATFORMS = Map.of( + "Windows", + "Windows NT 10.0; Win64; x64", + "Mac", + "Macintosh; Intel Mac OS X 10_15_7", + "Linux", + "X11; Linux x86_64"); + public static Map SAFARI_PLATFORMS = Map.of( + "Windows", + "Macintosh; Intel Mac OS X 10_15_7", + "Mac", + "Macintosh; Intel Mac OS X 10_15_7", + "Linux", + "Macintosh; Intel Mac OS X 10_15_7"); + // Platforms + public static Map> BROWSERS_PLATFORMS = Map.of( + "Firefox", FIREFOX_PLATFORMS, + "Chrome", CHROME_PLATFORMS, + "Safari", SAFARI_PLATFORMS + ); // Browsers public static Map BROWSERS_USER_AGENTS = Map.of( - "Firefox", "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/128.0", - "Chrome", "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", - "Safari", "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15" + "Firefox", "User-Agent: Mozilla/5.0 (%s) Gecko/20100101 Firefox/129.0", + "Chrome", "User-Agent: Mozilla/5.0 (%s) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36", + "Safari", "User-Agent: Mozilla/5.0 (%s) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15" ); public static Map BROWSERS_PROTOCOLS = Map.of( "Firefox", new String[]{"TLSv1.2", "TLSv1.3"}, diff --git a/src/main/java/net/portswigger/burp/extensions/TLSContextMenuItemsProvider.java b/src/main/java/net/portswigger/burp/extensions/TLSContextMenuItemsProvider.java index 45e4cff..cc8eae5 100644 --- a/src/main/java/net/portswigger/burp/extensions/TLSContextMenuItemsProvider.java +++ b/src/main/java/net/portswigger/burp/extensions/TLSContextMenuItemsProvider.java @@ -15,7 +15,6 @@ import java.util.Arrays; import java.util.List; import java.util.concurrent.ThreadPoolExecutor; -import java.util.stream.Collectors; public class TLSContextMenuItemsProvider implements ContextMenuItemsProvider { private ThreadPoolExecutor taskEngine; @@ -51,6 +50,10 @@ public List provideMenuItems(ContextMenuEvent contextMenuEvent) { menuItemList.add(item); } ); + String menuLabel = Utilities.enabledHTTPDowngrade() ? "Enable " : "Disable "; + JMenuItem downgradeMenu = new JMenuItem(menuLabel + Utilities.getResourceString("menu_downgrade")); + downgradeMenu.addActionListener(e -> downgradeHttp()); + menuItemList.add(downgradeMenu); JMenuItem item = new JMenuItem(Utilities.getResourceString("menu_brute_force")); item.addActionListener(new TriggerCipherGuesser(taskEngine, requestResponses)); @@ -63,7 +66,9 @@ public List provideMenuItems(ContextMenuEvent contextMenuEvent) { return null; } - + public void downgradeHttp(){ + Utilities.updateHTTPSettings(); + } public void addTLSCiphers(Browsers browser){ Utilities.updateTLSSettingsSync(Constants.BROWSERS_PROTOCOLS.get(browser.name), Constants.BROWSERS_CIPHERS.get(browser.name)); Utilities.updateProxySettingsSync(MatchAndReplace.create(browser)); diff --git a/src/main/java/net/portswigger/burp/extensions/TriggerCipherGuesser.java b/src/main/java/net/portswigger/burp/extensions/TriggerCipherGuesser.java index 75f4951..d13dc4b 100644 --- a/src/main/java/net/portswigger/burp/extensions/TriggerCipherGuesser.java +++ b/src/main/java/net/portswigger/burp/extensions/TriggerCipherGuesser.java @@ -2,15 +2,20 @@ import burp.api.montoya.core.Annotations; import burp.api.montoya.http.message.HttpRequestResponse; +import burp.api.montoya.http.message.responses.HttpResponse; import net.portswigger.burp.extensions.beens.Browsers; import net.portswigger.burp.extensions.beens.MatchAndReplace; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.concurrent.ThreadPoolExecutor; +import java.util.stream.Collectors; + +import static net.portswigger.burp.extensions.Constants.MAX_ATTEMPTS; public class TriggerCipherGuesser implements ActionListener, Runnable { private ThreadPoolExecutor taskEngine; @@ -48,12 +53,20 @@ public void run() { while (it.hasNext()) { HttpRequestResponse requestResponse = it.next(); String negotiation = Utilities.negotiation(protocol,ciphers); - HttpRequestResponse prob = Utilities.attemptRequest(requestResponse, negotiation); - if ( prob != null && Utilities.compareResponses(requestResponse, prob)) { + List probs = new ArrayList<>(); + for(int i = 0; i < MAX_ATTEMPTS; i++) { + HttpRequestResponse prob = Utilities.attemptRequest(requestResponse, negotiation); + probs.add(prob); + } + if ( !probs.isEmpty() && Utilities.compareResponses(requestResponse, probs)) { String comment = String.format( "|*| URL %s response was changed. Status code %s. TLS settings: %s", requestResponse.request().url(), - prob.response().statusCode(), + probs.stream() + .map(HttpRequestResponse::response) + .map(HttpResponse::statusCode) + .map(String::valueOf) + .reduce("",(partial,element) -> element + "," + partial), negotiation ); Utilities.log(comment); Utilities.addComment(requestResponse,negotiation); diff --git a/src/main/java/net/portswigger/burp/extensions/Utilities.java b/src/main/java/net/portswigger/burp/extensions/Utilities.java index d1e957e..1405fab 100644 --- a/src/main/java/net/portswigger/burp/extensions/Utilities.java +++ b/src/main/java/net/portswigger/burp/extensions/Utilities.java @@ -2,8 +2,12 @@ import burp.api.montoya.MontoyaApi; import burp.api.montoya.core.Annotations; +import burp.api.montoya.core.ByteArray; import burp.api.montoya.core.HighlightColor; +import burp.api.montoya.http.HttpMode; +import burp.api.montoya.http.HttpService; import burp.api.montoya.http.message.HttpRequestResponse; +import burp.api.montoya.http.message.requests.HttpRequest; import burp.api.montoya.http.message.responses.HttpResponse; import burp.api.montoya.http.message.responses.analysis.Attribute; import burp.api.montoya.proxy.ProxyHistoryFilter; @@ -19,6 +23,7 @@ import java.net.InetAddress; import java.net.URI; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Optional; import java.util.ResourceBundle; @@ -70,6 +75,25 @@ static void updateTLSSettingsSync(String[] protocols, String[] ciphers) { String serializedTLSSettings = gson.toJson(currentTLSSettings); montoyaApi.burpSuite().importProjectOptionsFromJson(serializedTLSSettings); } + static boolean enabledHTTPDowngrade() { + String project_settings = montoyaApi.burpSuite().exportProjectOptionsAsJson("project_options"); + TLSSettings currentTLSSettings = gson.fromJson(project_settings, TLSSettings.class); + return currentTLSSettings.enabledHTTPDowngrade(); + } + static void updateHTTPSettings() { + List rules = MatchAndReplace.createDowngradeRules(); + String proxy = montoyaApi.burpSuite().exportProjectOptionsAsJson("proxy.match_replace_rules"); + ProxySettings currentProxySettings = gson.fromJson(proxy, ProxySettings.class); + ProxySettings changedProxySettings = currentProxySettings.toggleHTTPDowngradeMatchAndReplace(rules); + String serializedProxySettings = gson.toJson(changedProxySettings); + montoyaApi.burpSuite().importProjectOptionsFromJson(serializedProxySettings); + + String project_settings = montoyaApi.burpSuite().exportProjectOptionsAsJson("project_options"); + TLSSettings currentTLSSettings = gson.fromJson(project_settings, TLSSettings.class); + currentTLSSettings.toggleHTTPSettings(); + String serializedTLSSettings = gson.toJson(currentTLSSettings); + montoyaApi.burpSuite().importProjectOptionsFromJson(serializedTLSSettings); + } static void importProject(String serializedSettings) { try { @@ -145,13 +169,35 @@ static HttpRequestResponse attemptRequest(HttpRequestResponse requestResponse, S } } - static boolean compareResponses(HttpRequestResponse baseRequest, HttpRequestResponse comparableResponse) { - if (baseRequest.response() == null || comparableResponse.response() == null) return false; - double P = 0.1; + static HttpRequestResponse unpredictable(List comparableResponses) { + HttpRequestResponse etalon = null; + double P = 0.2; + int base = -1; + for(HttpRequestResponse requestResponse: comparableResponses) { + if (requestResponse.hasResponse() && requestResponse.response() != null) { + Optional words = requestResponse.response().attributes(WORD_COUNT).stream().map(Attribute::value).findFirst(); + if (words.isPresent()) { + if (base == -1) { + base = words.get(); + etalon = requestResponse; + } else { + int diff = Math.abs(base - words.get()); + if (diff > Math.abs(base) * P) etalon = requestResponse; + } + } + } + } + return etalon; + } + + static boolean compareResponses(HttpRequestResponse baseRequest, List comparableResponses) { + HttpRequestResponse requestResponse = unpredictable(comparableResponses); + if (baseRequest.response() == null || requestResponse == null) return false; + double P = 0.2; int b = 0; int c = 0; List baseAttributes = baseRequest.response().attributes(WORD_COUNT); - List comparableAttributes = comparableResponse.response().attributes(WORD_COUNT); + List comparableAttributes = requestResponse.response().attributes(WORD_COUNT); Optional baseWordCount = baseAttributes.stream().map(Attribute::value).findFirst(); Optional comparableWordCount = comparableAttributes.stream().map(Attribute::value).findFirst(); if (baseWordCount.isPresent() && comparableWordCount.isPresent()) { @@ -159,7 +205,7 @@ static boolean compareResponses(HttpRequestResponse baseRequest, HttpRequestResp c = comparableWordCount.get(); } else { b = baseRequest.response().headers().size(); - c = comparableResponse.response().headers().size(); + c = requestResponse.response().headers().size(); } int diff = Math.abs(b - c); return diff > Math.abs(b) * P || diff > Math.abs(c) * P; @@ -194,7 +240,7 @@ public boolean matches(ProxyHttpRequestResponse requestResponse) { }); items.forEach(item -> { item.annotations().setNotes(comments); - item.annotations().setHighlightColor(HighlightColor.GREEN); + item.annotations().setHighlightColor(HighlightColor.RED); }); } static String getComment(HttpRequestResponse baseRequest) { diff --git a/src/main/java/net/portswigger/burp/extensions/beens/HTTP.java b/src/main/java/net/portswigger/burp/extensions/beens/HTTP.java new file mode 100644 index 0000000..7c8c36a --- /dev/null +++ b/src/main/java/net/portswigger/burp/extensions/beens/HTTP.java @@ -0,0 +1,19 @@ +package net.portswigger.burp.extensions.beens; + +import com.google.gson.annotations.Expose; + +public class HTTP { + private @Expose HTTP2 http2; + + public HTTP(HTTP2 http2) { + this.http2 = http2; + } + + public HTTP2 getHttp2() { + return http2; + } + + public void setHttp2(HTTP2 http2) { + this.http2 = http2; + } +} diff --git a/src/main/java/net/portswigger/burp/extensions/beens/HTTP2.java b/src/main/java/net/portswigger/burp/extensions/beens/HTTP2.java new file mode 100644 index 0000000..fd6f56b --- /dev/null +++ b/src/main/java/net/portswigger/burp/extensions/beens/HTTP2.java @@ -0,0 +1,19 @@ +package net.portswigger.burp.extensions.beens; + +import com.google.gson.annotations.Expose; + +public class HTTP2 { + private @Expose boolean enable_http2; + + public HTTP2(boolean enable_http2) { + this.enable_http2 = enable_http2; + } + + public boolean getEnableHTTP2() { + return enable_http2; + } + + public void setEnableHTTP2(boolean enable_http2) { + this.enable_http2 = enable_http2; + } +} diff --git a/src/main/java/net/portswigger/burp/extensions/beens/MatchAndReplace.java b/src/main/java/net/portswigger/burp/extensions/beens/MatchAndReplace.java index c17df1d..56dd045 100644 --- a/src/main/java/net/portswigger/burp/extensions/beens/MatchAndReplace.java +++ b/src/main/java/net/portswigger/burp/extensions/beens/MatchAndReplace.java @@ -3,6 +3,10 @@ import com.google.gson.annotations.Expose; import net.portswigger.burp.extensions.Constants; +import java.util.*; + +import static net.portswigger.burp.extensions.Constants.*; + public class MatchAndReplace { private @Expose String comment; private @Expose boolean enabled; @@ -20,14 +24,33 @@ public MatchAndReplace(String comment, boolean enabled, boolean is_simple_match, this.string_replace = string_replace; } + public static List createDowngradeRules(){ + List rules = new ArrayList<>(); + for(String header : MATCH_AND_REPLACE_REGEXP_HTTP2) { + rules.add(new MatchAndReplace( + String.format("HTTP2 Header %s downgrade rule", header), + true, + false, + Constants.MATCH_AND_REPLACE_RULE_TYPE, + header, + "" + )); + } + return rules; + } + public static MatchAndReplace create(Browsers browser){ + String platform = System.getProperty("os.name","Windows"); + OS optionalOS = Arrays.stream(OS.values()).filter(os -> platform.contains(os.name)).findFirst().get(); + String format = BROWSERS_USER_AGENTS.get(browser.name); + String value = BROWSERS_PLATFORMS.get(browser.name).get(optionalOS.name); return new MatchAndReplace( String.format("Emulate %s User-Agent", browser.name), true, false, Constants.MATCH_AND_REPLACE_RULE_TYPE, Constants.MATCH_AND_REPLACE_REGEXP, - Constants.BROWSERS_USER_AGENTS.get(browser.name) + String.format(format,value) ); } public boolean filterByComment(MatchAndReplace filter) { diff --git a/src/main/java/net/portswigger/burp/extensions/beens/OS.java b/src/main/java/net/portswigger/burp/extensions/beens/OS.java new file mode 100644 index 0000000..eb1f2bb --- /dev/null +++ b/src/main/java/net/portswigger/burp/extensions/beens/OS.java @@ -0,0 +1,12 @@ +package net.portswigger.burp.extensions.beens; + +public enum OS { + WINDOWS("Windows"), + MACOS("Mac"), + LINUX("Linux"); + public final String name; + + OS(String name) { + this.name = name; + } +} diff --git a/src/main/java/net/portswigger/burp/extensions/beens/ProjectOptions.java b/src/main/java/net/portswigger/burp/extensions/beens/ProjectOptions.java index a4c4280..524f0b1 100644 --- a/src/main/java/net/portswigger/burp/extensions/beens/ProjectOptions.java +++ b/src/main/java/net/portswigger/burp/extensions/beens/ProjectOptions.java @@ -4,6 +4,7 @@ public class ProjectOptions { private @Expose SSL ssl; + private @Expose HTTP http; public ProjectOptions(SSL ssl) { this.ssl = ssl; @@ -12,8 +13,14 @@ public ProjectOptions(SSL ssl) { public SSL getSsl() { return ssl; } + public HTTP getHTTP() { + return http; + } public void setSsl(SSL ssl) { this.ssl = ssl; } + public void setHTTP(HTTP http) { + this.http = http; + } } diff --git a/src/main/java/net/portswigger/burp/extensions/beens/Proxy.java b/src/main/java/net/portswigger/burp/extensions/beens/Proxy.java index 9826dc6..34d5ace 100644 --- a/src/main/java/net/portswigger/burp/extensions/beens/Proxy.java +++ b/src/main/java/net/portswigger/burp/extensions/beens/Proxy.java @@ -45,4 +45,19 @@ public void toggleMatchAndReplace(MatchAndReplace rule){ } setMatchReplaceRules(existing.toArray(new MatchAndReplace[0])); } + public void toggleHTTPDowngradeMatchAndReplace(List rules){ + List existing = new ArrayList<>(List.of(this.match_replace_rules)); + for(MatchAndReplace rule: rules) { + Optional found = existing.stream().filter(r -> r.filterByComment(rule)).findFirst(); + if (found.isEmpty()) { + existing.add(rule); + } else { + MatchAndReplace availableRule = found.get(); + existing.remove(availableRule); + availableRule.setEnabled(!availableRule.isEnabled()); + existing.add(availableRule); + } + } + setMatchReplaceRules(existing.toArray(new MatchAndReplace[0])); + } } diff --git a/src/main/java/net/portswigger/burp/extensions/beens/ProxySettings.java b/src/main/java/net/portswigger/burp/extensions/beens/ProxySettings.java index 5ce6c40..5ae3479 100644 --- a/src/main/java/net/portswigger/burp/extensions/beens/ProxySettings.java +++ b/src/main/java/net/portswigger/burp/extensions/beens/ProxySettings.java @@ -2,6 +2,8 @@ import com.google.gson.annotations.Expose; +import java.util.List; + public class ProxySettings { private final @Expose Proxy proxy; @@ -13,4 +15,9 @@ public ProxySettings toggleMatchAndReplace(MatchAndReplace rule) { existing.toggleMatchAndReplace(rule); return new ProxySettings(existing); } + public ProxySettings toggleHTTPDowngradeMatchAndReplace(List rules) { + Proxy existing = this.proxy; + existing.toggleHTTPDowngradeMatchAndReplace(rules); + return new ProxySettings(existing); + } } diff --git a/src/main/java/net/portswigger/burp/extensions/beens/TLSNegotiation.java b/src/main/java/net/portswigger/burp/extensions/beens/TLSNegotiation.java new file mode 100644 index 0000000..78b167f --- /dev/null +++ b/src/main/java/net/portswigger/burp/extensions/beens/TLSNegotiation.java @@ -0,0 +1,16 @@ +package net.portswigger.burp.extensions.beens; + +import java.util.Arrays; + +public record TLSNegotiation(String[] protocols, String[] ciphers) { + public TLSNegotiation { + } + + @Override + public String toString() { + return "TLSNegotiation{" + + "protocols=" + Arrays.toString(protocols) + + ", ciphers=" + Arrays.toString(ciphers) + + '}'; + } +} diff --git a/src/main/java/net/portswigger/burp/extensions/beens/TLSSettings.java b/src/main/java/net/portswigger/burp/extensions/beens/TLSSettings.java index 884d010..61ba0eb 100644 --- a/src/main/java/net/portswigger/burp/extensions/beens/TLSSettings.java +++ b/src/main/java/net/portswigger/burp/extensions/beens/TLSSettings.java @@ -27,4 +27,15 @@ public void addCiphers(String[] ciphers) { ssl.setNegotiation(negotiation); this.project_options.setSsl(ssl); } + + public void toggleHTTPSettings() { + HTTP http = this.project_options.getHTTP(); + boolean enabled = http.getHttp2().getEnableHTTP2(); + http.setHttp2(new HTTP2(!enabled)); + this.project_options.setHTTP(http); + } + + public boolean enabledHTTPDowngrade() { + return this.project_options.getHTTP().getHttp2().getEnableHTTP2(); + } } diff --git a/src/main/resources/strings.properties b/src/main/resources/strings.properties index a92bc80..fdcd212 100644 --- a/src/main/resources/strings.properties +++ b/src/main/resources/strings.properties @@ -2,6 +2,7 @@ tool_name=Bypass bot detection greetings=Bypass bot detection started error=Extension failed with exception! menu_brute_force=Brute force ciphers +menu_downgrade=downgrade HTTP2 network_preferences=net.portswigger.burp.extensions.bypass.bot.detection proxy_preferences=net.portswigger.burp.extensions.bypass.bot.detection.proxy loading=Loading custom Settings -> Network -> TLS Negotiation -> Use custom protocols and ciphers. Unload the extension to restore defaults!