├── .gitignore ├── .gradle ├── 8.10 │ ├── checksums │ │ └── checksums.lock │ ├── dependencies-accessors │ │ └── gc.properties │ ├── executionHistory │ │ ├── executionHistory.bin │ │ └── executionHistory.lock │ ├── expanded │ │ └── expanded.lock │ ├── fileChanges │ │ └── last-build.bin │ ├── fileHashes │ │ ├── fileHashes.bin │ │ ├── fileHashes.lock │ │ └── resourceHashesCache.bin │ └── gc.properties ├── buildOutputCleanup │ ├── buildOutputCleanup.lock │ ├── cache.properties │ └── outputFiles.bin ├── file-system.probe └── vcs-1 │ └── gc.properties ├── .idea ├── .gitignore ├── compiler.xml ├── gradle.xml ├── misc.xml └── vcs.xml ├── README.md ├── build.gradle ├── build ├── classes │ └── java │ │ └── main │ │ └── burpsuite │ │ ├── MenuItemsProvider.class │ │ ├── MyTableModel$LogEntry.class │ │ ├── MyTableModel.class │ │ ├── Settings$1.class │ │ ├── Settings$2.class │ │ ├── Settings$3.class │ │ ├── Settings$4.class │ │ ├── Settings$5.class │ │ ├── Settings$6.class │ │ ├── Settings$7.class │ │ ├── Settings.class │ │ ├── UnkeyInput$1.class │ │ ├── UnkeyInput$2.class │ │ ├── UnkeyInput$3.class │ │ ├── UnkeyInput.class │ │ └── proxyHandler.class ├── libs │ └── UnkeyInput-1.0.jar ├── resources │ └── main │ │ ├── Parameters.txt │ │ └── allHeaders.txt └── tmp │ ├── compileJava │ └── previous-compilation-data.bin │ └── jar │ └── MANIFEST.MF ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── images ├── 1.png ├── 2.png └── 3.png ├── settings.gradle └── src └── main ├── java └── burpsuite │ ├── MenuItemsProvider.java │ ├── MyTableModel.java │ ├── Settings.java │ ├── UnkeyInput.java │ └── proxyHandler.java └── resources ├── Parameters.txt └── allHeaders.txt /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gitignore -------------------------------------------------------------------------------- /.gradle/8.10/checksums/checksums.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/8.10/checksums/checksums.lock -------------------------------------------------------------------------------- /.gradle/8.10/dependencies-accessors/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/8.10/dependencies-accessors/gc.properties -------------------------------------------------------------------------------- /.gradle/8.10/executionHistory/executionHistory.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/8.10/executionHistory/executionHistory.bin -------------------------------------------------------------------------------- /.gradle/8.10/executionHistory/executionHistory.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/8.10/executionHistory/executionHistory.lock -------------------------------------------------------------------------------- /.gradle/8.10/expanded/expanded.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/8.10/expanded/expanded.lock -------------------------------------------------------------------------------- /.gradle/8.10/fileChanges/last-build.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gradle/8.10/fileHashes/fileHashes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/8.10/fileHashes/fileHashes.bin -------------------------------------------------------------------------------- /.gradle/8.10/fileHashes/fileHashes.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/8.10/fileHashes/fileHashes.lock -------------------------------------------------------------------------------- /.gradle/8.10/fileHashes/resourceHashesCache.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/8.10/fileHashes/resourceHashesCache.bin -------------------------------------------------------------------------------- /.gradle/8.10/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/8.10/gc.properties -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/buildOutputCleanup.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/buildOutputCleanup/buildOutputCleanup.lock -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/cache.properties: -------------------------------------------------------------------------------- 1 | #Tue Jan 07 13:12:14 EST 2025 2 | gradle.version=8.10 3 | -------------------------------------------------------------------------------- /.gradle/buildOutputCleanup/outputFiles.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/buildOutputCleanup/outputFiles.bin -------------------------------------------------------------------------------- /.gradle/file-system.probe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/file-system.probe -------------------------------------------------------------------------------- /.gradle/vcs-1/gc.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/.gradle/vcs-1/gc.properties -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Unkey Input

2 | 3 |

Burp suite extension to find unkey headers OR parameters

4 | 5 | 6 |

7 | 8 | 9 | 10 | 11 | 12 |
UnkeyInputUnkeyInput
13 |

14 | 15 |

16 | UnkeyInput 17 |

18 | 19 | 20 |

Features

21 | 22 | 23 |

1 - Unique cache key per every request

24 | 25 | 29 | 30 | 31 |

2 - add top HTTP headers to your incoming HTTP requests

32 | 33 | ```sh 34 | GET /?_parameter=372586408566 HTTP/1.1 35 | Host: 0ad800b603698249817511ea0076000a.web-security-academy.net 36 | User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/372586408566 Safari/372586408566 37 | Cookie: _Cookie=372586408566 38 | Pragma: akamai-x-check-cacheable,akamai-x-cache-on 39 | Fastly-Debug: 1 40 | X-Http-Forwarded-For: X-Http-Forwarded-For-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 41 | X-Forwarded-For-Original: X-Forwarded-For-Original-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 42 | X-Forwarded-Client-Ip: X-Forwarded-Client-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 43 | X-Cluster-Client-Ip: X-Cluster-Client-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 44 | X-Original-Forwarded-For: X-Original-Forwarded-For-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 45 | X-Wap-Client-Ip: X-Wap-Client-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 46 | Fastly-Client-Ip: Fastly-Client-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 47 | X-Client-Ip: X-Client-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 48 | X-Wap-Profile: X-Wap-Profile-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 49 | X-Proxyuser-Uri: X-Proxyuser-Uri-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 50 | X-Remote-Ip: X-Remote-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 51 | X-Wap-Network-Client-Ip: X-Wap-Network-Client-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 52 | X-Originating-Ip: X-Originating-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 53 | Client-Ip: Client-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 54 | X-Host: X-Host-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 55 | X-Forwarded-Uri: X-Forwarded-Uri-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 56 | Cf-Connecting-Ip: Cf-Connecting-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 57 | X-True-Ip: X-True-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 58 | X-Rewrite-Url: X-Rewrite-Url-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 59 | X-Original-Url: X-Original-Url-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 60 | X-Proxyuser-Ip: X-Proxyuser-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 61 | X-Proxyuser-Host: X-Proxyuser-Host-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 62 | Referer: Referer-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 63 | X-Forwarded-Host: X-Forwarded-Host-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 64 | X-Remote-Addr: X-Remote-Addr-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 65 | X-Original-Host: X-Original-Host-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 66 | X-Originating-Host: X-Originating-Host-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 67 | True-Client-Ip: True-Client-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 68 | X-Real-Host: X-Real-Host-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 69 | Akamai-Client-Ip: Akamai-Client-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 70 | X-Forwarded-Path: X-Forwarded-Path-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 71 | X-Original-Cookie: X-Original-Cookie-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 72 | X-Forwarded-By: X-Forwarded-By-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 73 | Forwarded: Forwarded-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 74 | X-Forwarded-For: X-Forwarded-For-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 75 | X-Original-User-Agent: X-Original-User-Agent-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 76 | X-Real-Ip: X-Real-Ip-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 77 | X-Forwarded-Server: X-Forwarded-Server-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 78 | X-Original-Referer: X-Original-Referer-%3Cxss%3E%253Cxss%253E\u003Cxss\u003E 79 | ``` 80 | 81 |

3 - Contain context menu to fuzz

82 |
    83 |
  • TitleCase Headers
  • 84 |
  • LowerCase Headers
  • 85 |
  • UpperCase Headers
  • 86 |
  • Hyphen to Underscore
  • 87 |
  • Duplicate Headers
  • 88 |
  • Hex to Headers
  • 89 |
      90 |
    • Hex Before Headers
    • 91 |
    • Hex After Headers
    • 92 |
    93 |
  • Duplicate Header With Space
  • 94 |
  • Fuzz Parameters
  • 95 |
      96 |
    • Query
    • 97 |
    • Body
    • 98 |
    99 |
  • Fuzz Cookie
  • 100 |
101 | 102 |

Reference

103 |

104 | Beyond Web Caching Vulnerabilities 105 |

106 | 107 |

© Copyright

108 | 109 |

110 | 111 |

112 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | group = 'burpsuite' 6 | version = '1.0' 7 | 8 | 9 | repositories { 10 | mavenCentral() 11 | } 12 | 13 | dependencies { 14 | implementation 'net.portswigger.burp.extensions:montoya-api:+' 15 | } 16 | 17 | 18 | jar { 19 | from { 20 | configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } 21 | } 22 | } -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/MenuItemsProvider.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/MenuItemsProvider.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/MyTableModel$LogEntry.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/MyTableModel$LogEntry.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/MyTableModel.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/MyTableModel.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/Settings$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/Settings$1.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/Settings$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/Settings$2.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/Settings$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/Settings$3.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/Settings$4.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/Settings$4.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/Settings$5.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/Settings$5.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/Settings$6.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/Settings$6.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/Settings$7.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/Settings$7.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/Settings.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/Settings.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/UnkeyInput$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/UnkeyInput$1.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/UnkeyInput$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/UnkeyInput$2.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/UnkeyInput$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/UnkeyInput$3.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/UnkeyInput.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/UnkeyInput.class -------------------------------------------------------------------------------- /build/classes/java/main/burpsuite/proxyHandler.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/classes/java/main/burpsuite/proxyHandler.class -------------------------------------------------------------------------------- /build/libs/UnkeyInput-1.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/libs/UnkeyInput-1.0.jar -------------------------------------------------------------------------------- /build/tmp/compileJava/previous-compilation-data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/build/tmp/compileJava/previous-compilation-data.bin -------------------------------------------------------------------------------- /build/tmp/jar/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jan 07 13:12:09 EST 2025 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/images/1.png -------------------------------------------------------------------------------- /images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/images/2.png -------------------------------------------------------------------------------- /images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xAwali/UnkeyInput/20a9ce5f381dc8770b37f9bec6a5c0921672e5f6/images/3.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'UnkeyInput' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/burpsuite/MenuItemsProvider.java: -------------------------------------------------------------------------------- 1 | package burpsuite; 2 | 3 | import burp.api.montoya.MontoyaApi; 4 | import burp.api.montoya.http.message.HttpRequestResponse; 5 | import burp.api.montoya.http.message.StatusCodeClass; 6 | import burp.api.montoya.http.message.params.HttpParameterType; 7 | import burp.api.montoya.http.message.requests.HttpRequest; 8 | import burp.api.montoya.persistence.PersistedObject; 9 | import burp.api.montoya.ui.contextmenu.ContextMenuEvent; 10 | import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider; 11 | import burp.api.montoya.ui.contextmenu.InvocationType; 12 | import javax.swing.*; 13 | import java.awt.*; 14 | import java.io.BufferedReader; 15 | import java.io.InputStream; 16 | import java.io.InputStreamReader; 17 | import java.util.ArrayList; 18 | import java.util.Collections; 19 | import java.util.List; 20 | import java.util.concurrent.ExecutorService; 21 | import java.util.concurrent.Executors; 22 | import java.util.concurrent.ThreadLocalRandom; 23 | 24 | import static burp.api.montoya.http.message.params.HttpParameter.*; 25 | import static burpsuite.UnkeyInput.*; 26 | 27 | public class MenuItemsProvider implements ContextMenuItemsProvider { 28 | 29 | private final MontoyaApi api; 30 | private final MyTableModel table; 31 | 32 | private static final String[] HEADERS_TO_REMOVE = { 33 | "Akamai-Client-Ip", "Cf-Connecting-Ip", "Client-Ip", "Fastly-Client-Ip", "Forwarded", "Referer", "True-Client-Ip", 34 | "X-Client-Ip", "X-Cluster-Client-Ip", "X-Forwarded-By", "X-Forwarded-Client-Ip", "X-Forwarded-For", "X-Forwarded-For-Original", 35 | "X-Forwarded-Host", "X-Forwarded-Path", "X-Forwarded-Server", "X-Forwarded-Uri", "X-Host", "X-Http-Forwarded-For", 36 | "X-Original-Cookie", "X-Original-Forwarded-For", "X-Original-Host", "X-Original-Referer", "X-Original-Url", "X-Original-User-Agent", 37 | "X-Originating-Host", "X-Originating-Ip", "X-Proxyuser-Host", "X-Proxyuser-Ip", "X-Proxyuser-Uri", "X-Real-Host", "X-Real-Ip", 38 | "X-Remote-Addr", "X-Remote-Ip", "X-Rewrite-Url", "X-True-Ip", "X-Wap-Client-Ip", "X-Wap-Network-Client-Ip", "X-Wap-Profile" 39 | }; 40 | 41 | private static final String[] CACHE_HEADERS = { 42 | "Age", "CDN-Cache", "CF-Cache-Status", "Server-Timing", "X-Cache", "X-Cache-Info", "X-Cache-Remote", "X-Check-Cacheable", 43 | "X-Drupal-Cache", "X-Drupal-Dynamic-Cache", "X-Proxy-Cache", "X-Rack-Cache", "Akamai-Cache-Status" 44 | }; 45 | 46 | PersistedObject persistence; 47 | private List additionalHeaders; 48 | private List parameters; 49 | 50 | public MenuItemsProvider(MontoyaApi api, MyTableModel table, PersistedObject persist) { 51 | this.api = api; 52 | this.table = table; 53 | this.additionalHeaders = loadAdditionalHeaders(); 54 | this.parameters = loadParameters(); 55 | this.persistence = persist; 56 | 57 | 58 | } 59 | 60 | // Load additional headers from the resources folder 61 | private List loadAdditionalHeaders() { 62 | List headers = new ArrayList<>(); 63 | try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("allHeaders.txt"); 64 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { 65 | String line; 66 | while ((line = reader.readLine()) != null) { 67 | headers.add(line.trim()); 68 | } 69 | } catch (Exception e) { 70 | api.logging().logToError("Failed to load additional headers: " + e.getMessage()); 71 | } 72 | return headers; 73 | } 74 | 75 | // Load parameters from the resources folder 76 | private List loadParameters() { 77 | List parameters = new ArrayList<>(); 78 | try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream("Parameters.txt"); 79 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { 80 | String line; 81 | while ((line = reader.readLine()) != null) { 82 | parameters.add(line.trim()); 83 | } 84 | } catch (Exception e) { 85 | api.logging().logToError("Failed to load parameters: " + e.getMessage()); 86 | } 87 | return parameters; 88 | } 89 | 90 | @Override 91 | public List provideMenuItems(ContextMenuEvent event) { 92 | if (event.isFrom(InvocationType.PROXY_HISTORY)) { 93 | List menuItemList = new ArrayList<>(); 94 | 95 | // Existing menu items 96 | JMenuItem fuzzHeaders = new JMenuItem("TitleCase Headers"); 97 | fuzzHeaders.addActionListener(l -> titleCaseHeaders(event)); 98 | menuItemList.add(fuzzHeaders); 99 | 100 | JMenuItem lowerCaseHeaders = new JMenuItem("LowerCase Headers"); 101 | lowerCaseHeaders.addActionListener(l -> upperORlower(event, true)); 102 | menuItemList.add(lowerCaseHeaders); 103 | 104 | JMenuItem upperCaseHeaders = new JMenuItem("UpperCase Headers"); 105 | upperCaseHeaders.addActionListener(l -> upperORlower(event, false)); 106 | menuItemList.add(upperCaseHeaders); 107 | 108 | JMenuItem convertHyphenToUnderscore = new JMenuItem("Convert Hyphen to Underscore"); 109 | convertHyphenToUnderscore.addActionListener(l -> convertHyphenToUnderscore(event)); 110 | menuItemList.add(convertHyphenToUnderscore); 111 | 112 | JMenuItem duplicateHeader = new JMenuItem("Duplicate Header"); 113 | duplicateHeader.addActionListener(l -> duplicateHeader(event)); 114 | menuItemList.add(duplicateHeader); 115 | 116 | // Add new menu item for Fuzz Parameters with submenus 117 | JMenu addHexToHeader = new JMenu("Add Hex to Headers"); 118 | 119 | JMenuItem HexHeaderValue = new JMenuItem("Hex Before Headers"); 120 | HexHeaderValue.addActionListener(l -> HexHeaderValue(event)); 121 | addHexToHeader.add(HexHeaderValue); 122 | 123 | JMenuItem HeaderHexValue = new JMenuItem("Hex After Headers"); 124 | HeaderHexValue.addActionListener(l -> HeaderHexValue(event)); 125 | addHexToHeader.add(HeaderHexValue); 126 | 127 | menuItemList.add(addHexToHeader); 128 | 129 | JMenuItem duplicateHeaderWithSpace = new JMenuItem("Duplicate Header With Space"); 130 | duplicateHeaderWithSpace.addActionListener(l -> duplicateHeaderWithSpace(event)); 131 | menuItemList.add(duplicateHeaderWithSpace); 132 | 133 | // Add new menu item for Fuzz Parameters with submenus 134 | JMenu fuzzParametersMenu = new JMenu("Fuzz Parameters"); 135 | // Submenu: Query 136 | JMenuItem queryMenuItem = new JMenuItem("Query"); 137 | queryMenuItem.addActionListener(l -> fuzzQuery(event)); 138 | fuzzParametersMenu.add(queryMenuItem); 139 | 140 | // Submenu: Body 141 | JMenu bodyMenu = new JMenu("Body"); 142 | 143 | // Submenu under Body: Url-Encoding 144 | JMenuItem urlEncodingMenuItem = new JMenuItem("urlencoded"); 145 | urlEncodingMenuItem.addActionListener(l -> fuzzBodyUrlEncoding(event)); 146 | bodyMenu.add(urlEncodingMenuItem); 147 | 148 | // Submenu under Body: json 149 | JMenuItem jsonMenuItem = new JMenuItem("json"); 150 | jsonMenuItem.addActionListener(l -> fuzzBodyJson(event)); 151 | bodyMenu.add(jsonMenuItem); 152 | 153 | // Submenu under Body: xml 154 | JMenuItem xmlMenuItem = new JMenuItem("xml"); 155 | xmlMenuItem.addActionListener(l -> fuzzBodyXml(event)); 156 | bodyMenu.add(xmlMenuItem); 157 | 158 | fuzzParametersMenu.add(bodyMenu); 159 | menuItemList.add(fuzzParametersMenu); 160 | 161 | JMenuItem fuzzCookie = new JMenuItem("Fuzz Cookie"); 162 | fuzzCookie.addActionListener(l -> fuzzCookie(event)); 163 | menuItemList.add(fuzzCookie); 164 | 165 | 166 | 167 | return menuItemList; 168 | } 169 | return Collections.emptyList(); 170 | } 171 | 172 | private List getAllHeaders() { 173 | List allHeaders = new ArrayList<>(); 174 | Collections.addAll(allHeaders, HEADERS_TO_REMOVE); 175 | allHeaders.addAll(additionalHeaders); // Use headers loaded from the file 176 | return allHeaders; 177 | } 178 | 179 | private boolean isCached(HttpRequestResponse httpRequestResponse) { 180 | if (httpRequestResponse.response().body().toString().contains(persistence.getString(YOUR_MATCH)) || httpRequestResponse.response().headers().toString().contains(persistence.getString(YOUR_MATCH))) { 181 | for (String header : CACHE_HEADERS) { 182 | if (httpRequestResponse.response().hasHeader(header)) { 183 | return true; 184 | } 185 | } 186 | } 187 | return false; 188 | } 189 | 190 | private boolean isNOTCached(HttpRequestResponse httpRequestResponse) { 191 | if (httpRequestResponse.response().body().toString().contains(persistence.getString(YOUR_MATCH))) { 192 | if(httpRequestResponse.hasResponse() && (!httpRequestResponse.response().isStatusCodeClass(StatusCodeClass.CLASS_3XX_REDIRECTION))){ 193 | return true; 194 | } 195 | } 196 | return false; 197 | } 198 | 199 | 200 | private List> splitIntoChunks(T[] array, int chunkSize) { 201 | List> chunks = new ArrayList<>(); 202 | for (int i = 0; i < array.length; i += chunkSize) { 203 | List chunk = new ArrayList<>(); 204 | for (int j = i; j < Math.min(i + chunkSize, array.length); j++) { 205 | chunk.add(array[j]); 206 | } 207 | chunks.add(chunk); 208 | } 209 | return chunks; 210 | } 211 | 212 | private void titleCaseHeaders(ContextMenuEvent event) { 213 | List requestResponses = event.selectedRequestResponses(); 214 | if (requestResponses.isEmpty()) { 215 | return; 216 | } 217 | 218 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 219 | 220 | List allHeaders = getAllHeaders(); 221 | List> headerChunks = splitIntoChunks(allHeaders.toArray(new String[0]), persistence.getInteger(YOUR_HEADERS_PER_REQUEST)); 222 | 223 | for (HttpRequestResponse requestResponse : requestResponses) { 224 | executorService.submit(() -> { 225 | try { 226 | HttpRequest baseRequest = requestResponse.request(); 227 | 228 | // Remove headers from HEADERS_TO_REMOVE 229 | for (String header : HEADERS_TO_REMOVE) { 230 | baseRequest = baseRequest.withRemovedHeader(header); 231 | } 232 | // Process each chunk 233 | for (List chunk : headerChunks) { 234 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 235 | HttpRequest chunkRequest = baseRequest.withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 236 | .withUpdatedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 237 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 238 | 239 | for (String header : chunk) { 240 | String headerValue = header + "-" + persistence.getString(YOUR_PAYLOAD); 241 | chunkRequest = chunkRequest.withHeader(header, headerValue); 242 | } 243 | 244 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 245 | 246 | if (isCached(modifiedRequestResponse)) { 247 | table.add(modifiedRequestResponse,true); 248 | } else if (isNOTCached(modifiedRequestResponse)) { 249 | table.add(modifiedRequestResponse,false); 250 | } 251 | } 252 | } catch (Exception e) { 253 | api.logging().logToError("Failed to send request: " + e.getMessage()); 254 | } 255 | }); 256 | } 257 | executorService.shutdown(); 258 | } 259 | 260 | private void upperORlower(ContextMenuEvent event, boolean toLowerCase) { 261 | List requestResponses = event.selectedRequestResponses(); 262 | if (requestResponses.isEmpty()) { 263 | return; 264 | } 265 | 266 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 267 | 268 | List allHeaders = getAllHeaders(); // Use combined headers 269 | List> headerChunks = splitIntoChunks(allHeaders.toArray(new String[0]), persistence.getInteger(YOUR_HEADERS_PER_REQUEST)); 270 | 271 | for (HttpRequestResponse requestResponse : requestResponses) { 272 | executorService.submit(() -> { 273 | try { 274 | HttpRequest baseRequest = requestResponse.request(); 275 | 276 | // Remove headers from HEADERS_TO_REMOVE 277 | for (String header : HEADERS_TO_REMOVE) { 278 | baseRequest = baseRequest.withRemovedHeader(header); 279 | } 280 | // Process each chunk 281 | for (List chunk : headerChunks) { 282 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 283 | HttpRequest chunkRequest = baseRequest.withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 284 | .withUpdatedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 285 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 286 | 287 | for (String header : chunk) { 288 | String headerValue = header + "-" + persistence.getString(YOUR_PAYLOAD); // Set value to "header-xxxxxxxxxxxxxx" 289 | chunkRequest = chunkRequest.withHeader(toLowerCase ? header.toLowerCase() : header.toUpperCase(), headerValue); 290 | } 291 | 292 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 293 | 294 | if (isCached(modifiedRequestResponse)) { 295 | table.add(modifiedRequestResponse,true); 296 | } else if (isNOTCached(modifiedRequestResponse)) { 297 | table.add(modifiedRequestResponse,false); 298 | } 299 | } 300 | } catch (Exception e) { 301 | api.logging().logToError("Failed to send request: " + e.getMessage()); 302 | } 303 | }); 304 | } 305 | executorService.shutdown(); 306 | } 307 | 308 | 309 | private void convertHyphenToUnderscore(ContextMenuEvent event) { 310 | List requestResponses = event.selectedRequestResponses(); 311 | if (requestResponses.isEmpty()) { 312 | return; 313 | } 314 | 315 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 316 | 317 | List allHeaders = getAllHeaders(); // Use combined headers 318 | List> headerChunks = splitIntoChunks(allHeaders.toArray(new String[0]), persistence.getInteger(YOUR_HEADERS_PER_REQUEST)); 319 | 320 | for (HttpRequestResponse requestResponse : requestResponses) { 321 | executorService.submit(() -> { 322 | try { 323 | HttpRequest baseRequest = requestResponse.request(); 324 | 325 | // Remove headers from HEADERS_TO_REMOVE 326 | for (String header : HEADERS_TO_REMOVE) { 327 | baseRequest = baseRequest.withRemovedHeader(header); 328 | } 329 | // Process each chunk 330 | for (List chunk : headerChunks) { 331 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 332 | HttpRequest chunkRequest = baseRequest.withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 333 | .withUpdatedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 334 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 335 | 336 | for (String header : chunk) { 337 | if (header.contains("-")) { // Only process headers containing hyphens 338 | String newHeader = header.replace("-", "_"); // Convert hyphens to underscores 339 | String headerValue = header + "-" + persistence.getString(YOUR_PAYLOAD); // Set value to "header-xxxxxxxxxxxxxx" 340 | chunkRequest = chunkRequest.withHeader(newHeader, headerValue); 341 | } 342 | } 343 | 344 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 345 | 346 | if (isCached(modifiedRequestResponse)) { 347 | table.add(modifiedRequestResponse,true); 348 | } else if (isNOTCached(modifiedRequestResponse)) { 349 | table.add(modifiedRequestResponse,false); 350 | } 351 | } 352 | } catch (Exception e) { 353 | api.logging().logToError("Failed to send request: " + e.getMessage()); 354 | } 355 | }); 356 | } 357 | executorService.shutdown(); 358 | } 359 | 360 | private void duplicateHeader(ContextMenuEvent event) { 361 | List requestResponses = event.selectedRequestResponses(); 362 | if (requestResponses.isEmpty()) { 363 | return; 364 | } 365 | 366 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 367 | 368 | List allHeaders = getAllHeaders(); // Use combined headers 369 | List> headerChunks = splitIntoChunks(allHeaders.toArray(new String[0]), persistence.getInteger(YOUR_HEADERS_PER_REQUEST)); 370 | 371 | for (HttpRequestResponse requestResponse : requestResponses) { 372 | executorService.submit(() -> { 373 | try { 374 | HttpRequest baseRequest = requestResponse.request(); 375 | 376 | // Remove headers from HEADERS_TO_REMOVE 377 | for (String header : HEADERS_TO_REMOVE) { 378 | baseRequest = baseRequest.withRemovedHeader(header); 379 | } 380 | // Process each chunk 381 | for (List chunk : headerChunks) { 382 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 383 | HttpRequest chunkRequest = baseRequest.withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 384 | .withUpdatedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 385 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 386 | 387 | for (String header : chunk) { 388 | String headerValue = header + "-" + persistence.getString(YOUR_PAYLOAD); // Set value to "header-xxxxxxxxxxxxxx" 389 | chunkRequest = chunkRequest.withAddedHeader(header, headerValue); // Add the original header 390 | chunkRequest = chunkRequest.withAddedHeader(header, headerValue); // Add the duplicate header 391 | } 392 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 393 | if (isCached(modifiedRequestResponse)) { 394 | table.add(modifiedRequestResponse,true); 395 | } else if (isNOTCached(modifiedRequestResponse)) { 396 | table.add(modifiedRequestResponse,false); 397 | } 398 | } 399 | } catch (Exception e) { 400 | api.logging().logToError("Failed to send request: " + e.getMessage()); 401 | } 402 | }); 403 | } 404 | executorService.shutdown(); 405 | } 406 | 407 | 408 | private void HexHeaderValue(ContextMenuEvent event) { 409 | List requestResponses = event.selectedRequestResponses(); 410 | if (requestResponses.isEmpty()) { 411 | return; 412 | } 413 | 414 | // Define the hex values for non-printable characters 415 | int[] hexValues = {0x1, 0x4, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0x1F, 0x20, 0x7F, 0xA0, 0xFF}; 416 | 417 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 418 | 419 | 420 | List allHeaders = getAllHeaders(); // Use combined headers 421 | List> headerChunks = splitIntoChunks(allHeaders.toArray(new String[0]), persistence.getInteger(YOUR_HEADERS_PER_REQUEST)); 422 | 423 | for (HttpRequestResponse requestResponse : requestResponses) { 424 | executorService.submit(() -> { 425 | try { 426 | 427 | HttpRequest baseRequest = requestResponse.request(); 428 | // Remove headers from HEADERS_TO_REMOVE 429 | for (String header : HEADERS_TO_REMOVE) { 430 | baseRequest = baseRequest.withRemovedHeader(header); 431 | } 432 | // Process each chunk 433 | for (List chunk : headerChunks) { 434 | // Create a base request with random parameters 435 | // Iterate through hex values and send a separate request for each 436 | for (int hexValue : hexValues) { 437 | // Convert hex value to a non-printable character 438 | char nonPrintableChar = (char) hexValue; 439 | 440 | // Create a copy of the base request for this iteration 441 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 442 | 443 | HttpRequest chunkRequest = baseRequest 444 | .withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 445 | .withUpdatedParameters(cookieParameter("_Cookie", String.valueOf(randomNumber))) 446 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 447 | // Add non-printable character to each header in the chunk 448 | for (String header : chunk) { 449 | // Prepend the non-printable character to the header name 450 | String newHeaderName = nonPrintableChar + header; 451 | String headerValue = header + "-" + persistence.getString(YOUR_PAYLOAD); // Set value to "header-xxxxxxxxxxxxxx" 452 | // Add the modified header to the request 453 | chunkRequest = chunkRequest.withHeader(newHeaderName, headerValue); 454 | } 455 | // Send the modified request 456 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 457 | 458 | // Check if the response body is valid and add to the table 459 | if (isCached(modifiedRequestResponse)) { 460 | table.add(modifiedRequestResponse,true); 461 | } else if (isNOTCached(modifiedRequestResponse)) { 462 | table.add(modifiedRequestResponse,false); 463 | } 464 | } 465 | } 466 | } catch (Exception e) { 467 | api.logging().logToError("Failed to send request: " + e.getMessage()); 468 | } 469 | }); 470 | } 471 | executorService.shutdown(); 472 | } 473 | 474 | 475 | 476 | private void HeaderHexValue(ContextMenuEvent event) { 477 | List requestResponses = event.selectedRequestResponses(); 478 | if (requestResponses.isEmpty()) { 479 | return; 480 | } 481 | 482 | // Define the hex values for non-printable characters 483 | int[] hexValues = {0x1, 0x4, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0x1F, 0x20, 0x7F, 0xA0, 0xFF}; 484 | 485 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 486 | 487 | 488 | List allHeaders = getAllHeaders(); // Use combined headers 489 | List> headerChunks = splitIntoChunks(allHeaders.toArray(new String[0]), persistence.getInteger(YOUR_HEADERS_PER_REQUEST)); 490 | 491 | for (HttpRequestResponse requestResponse : requestResponses) { 492 | executorService.submit(() -> { 493 | try { 494 | 495 | HttpRequest baseRequest = requestResponse.request(); 496 | // Remove headers from HEADERS_TO_REMOVE 497 | for (String header : HEADERS_TO_REMOVE) { 498 | baseRequest = baseRequest.withRemovedHeader(header); 499 | } 500 | 501 | // Process each chunk 502 | for (List chunk : headerChunks) { 503 | 504 | // Create a base request with random parameters 505 | 506 | // Iterate through hex values and send a separate request for each 507 | for (int hexValue : hexValues) { 508 | // Convert hex value to a non-printable character 509 | char nonPrintableChar = (char) hexValue; 510 | 511 | // Create a copy of the base request for this iteration 512 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 513 | 514 | HttpRequest chunkRequest = baseRequest 515 | .withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 516 | .withUpdatedParameters(cookieParameter("_Cookie", String.valueOf(randomNumber))) 517 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 518 | // Add non-printable character to each header in the chunk 519 | for (String header : chunk) { 520 | // Prepend the non-printable character to the header name 521 | String newHeaderName = header + nonPrintableChar; 522 | String headerValue = header + "-" + persistence.getString(YOUR_PAYLOAD); // Set value to "header-xxxxxxxxxxxxxx" 523 | // Add the modified header to the request 524 | chunkRequest = chunkRequest.withHeader(newHeaderName, headerValue); 525 | } 526 | // Send the modified request 527 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 528 | 529 | // Check if the response body is valid and add to the table 530 | if (isCached(modifiedRequestResponse)) { 531 | table.add(modifiedRequestResponse,true); 532 | } else if (isNOTCached(modifiedRequestResponse)) { 533 | table.add(modifiedRequestResponse,false); 534 | } 535 | } 536 | } 537 | } catch (Exception e) { 538 | api.logging().logToError("Failed to send request: " + e.getMessage()); 539 | } 540 | }); 541 | } 542 | executorService.shutdown(); 543 | } 544 | 545 | 546 | private void duplicateHeaderWithSpace(ContextMenuEvent event) { 547 | List requestResponses = event.selectedRequestResponses(); 548 | if (requestResponses.isEmpty()) { 549 | return; 550 | } 551 | 552 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 553 | 554 | 555 | List allHeaders = getAllHeaders(); // Use combined headers 556 | List> headerChunks = splitIntoChunks(allHeaders.toArray(new String[0]), persistence.getInteger(YOUR_HEADERS_PER_REQUEST)); 557 | 558 | for (HttpRequestResponse requestResponse : requestResponses) { 559 | executorService.submit(() -> { 560 | try { 561 | HttpRequest baseRequest = requestResponse.request(); 562 | 563 | // Remove headers from HEADERS_TO_REMOVE 564 | for (String header : HEADERS_TO_REMOVE) { 565 | baseRequest = baseRequest.withRemovedHeader(header); 566 | } 567 | // Process each chunk 568 | for (List chunk : headerChunks) { 569 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 570 | HttpRequest chunkRequest = baseRequest.withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 571 | .withUpdatedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 572 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 573 | 574 | for (String header : chunk) { 575 | String headerValue = header + "-" + persistence.getString(YOUR_PAYLOAD); // Set value to "header-xxxxxxxxxxxxxx" 576 | String newHeader = " " + header; // Add space to header name 577 | chunkRequest = chunkRequest.withAddedHeader(newHeader, headerValue); // Add the original header 578 | chunkRequest = chunkRequest.withAddedHeader(header, headerValue); // Add the duplicate header 579 | } 580 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 581 | if (isCached(modifiedRequestResponse)) { 582 | table.add(modifiedRequestResponse,true); 583 | } else if (isNOTCached(modifiedRequestResponse)) { 584 | table.add(modifiedRequestResponse,false); 585 | } 586 | } 587 | } catch (Exception e) { 588 | api.logging().logToError("Failed to send request: " + e.getMessage()); 589 | } 590 | }); 591 | } 592 | executorService.shutdown(); 593 | } 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | private void fuzzCookie(ContextMenuEvent event) { 602 | List requestResponses = event.selectedRequestResponses(); 603 | if (requestResponses.isEmpty()) { 604 | return; 605 | } 606 | 607 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 608 | 609 | 610 | List parameters = loadParameters(); // Load parameters from the file 611 | List> parameterChunks = splitIntoChunks(parameters.toArray(new String[0]), persistence.getInteger(YOUR_PARAMETERS_COOKIE_PER_REQUEST)); 612 | 613 | for (HttpRequestResponse requestResponse : requestResponses) { 614 | executorService.submit(() -> { 615 | try { 616 | HttpRequest baseRequest = requestResponse.request(); 617 | 618 | // Remove unwanted headers 619 | for (String header : HEADERS_TO_REMOVE) { 620 | baseRequest = baseRequest.withRemovedHeader(header); 621 | } 622 | 623 | // Process each chunk of 50 parameters 624 | for (List chunk : parameterChunks) { 625 | // Create a new request with the current chunk of parameters 626 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 627 | HttpRequest chunkRequest = baseRequest.withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 628 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 629 | 630 | // Add each parameter in the chunk to the request 631 | for (String parameter : chunk) { 632 | chunkRequest = chunkRequest.withAddedParameters(cookieParameter(parameter, persistence.getString(YOUR_PAYLOAD))); 633 | } 634 | 635 | // Send the modified request 636 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 637 | 638 | // Check if the response is valid and add it to the table 639 | if (isCached(modifiedRequestResponse)) { 640 | table.add(modifiedRequestResponse,true); 641 | } else if (isNOTCached(modifiedRequestResponse)) { 642 | table.add(modifiedRequestResponse,false); 643 | } 644 | } 645 | } catch (Exception e) { 646 | api.logging().logToError("Failed to send request: " + e.getMessage()); 647 | } 648 | }); 649 | } 650 | executorService.shutdown(); 651 | } 652 | 653 | 654 | 655 | 656 | // Example action methods for the new menu items 657 | private void fuzzQuery(ContextMenuEvent event) { 658 | List requestResponses = event.selectedRequestResponses(); 659 | if (requestResponses.isEmpty()) { 660 | return; 661 | } 662 | 663 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 664 | 665 | List parameters = loadParameters(); // Load parameters from the file 666 | List> parameterChunks = splitIntoChunks(parameters.toArray(new String[0]), persistence.getInteger(YOUR_PARAMETERS_QUERY_PER_REQUEST)); 667 | 668 | for (HttpRequestResponse requestResponse : requestResponses) { 669 | executorService.submit(() -> { 670 | try { 671 | HttpRequest baseRequest = requestResponse.request(); 672 | 673 | // Remove unwanted headers 674 | for (String header : HEADERS_TO_REMOVE) { 675 | baseRequest = baseRequest.withRemovedHeader(header); 676 | } 677 | 678 | // Process each chunk of 50 parameters 679 | for (List chunk : parameterChunks) { 680 | // Create a new request with the current chunk of parameters 681 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 682 | HttpRequest chunkRequest = baseRequest 683 | .withUpdatedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 684 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 685 | 686 | // Add each parameter in the chunk to the request 687 | for (String parameter : chunk) { 688 | chunkRequest = chunkRequest.withAddedParameters(parameter(parameter, persistence.getString(YOUR_PAYLOAD), HttpParameterType.URL)); 689 | } 690 | 691 | // Send the modified request 692 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 693 | 694 | // Check if the response is valid and add it to the table 695 | if (isCached(modifiedRequestResponse)) { 696 | table.add(modifiedRequestResponse,true); 697 | } else if (isNOTCached(modifiedRequestResponse)) { 698 | table.add(modifiedRequestResponse,false); 699 | } 700 | } 701 | } catch (Exception e) { 702 | api.logging().logToError("Failed to send request: " + e.getMessage()); 703 | } 704 | }); 705 | } 706 | executorService.shutdown(); 707 | } // Add your logic here 708 | 709 | 710 | private void fuzzBodyUrlEncoding(ContextMenuEvent event) { 711 | List requestResponses = event.selectedRequestResponses(); 712 | if (requestResponses.isEmpty()) { 713 | return; 714 | } 715 | 716 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 717 | 718 | 719 | List parameters = loadParameters(); // Load parameters from the file 720 | List> parameterChunks = splitIntoChunks(parameters.toArray(new String[0]), persistence.getInteger(YOUR_PARAMETERS_BODY_PER_REQUEST)); 721 | 722 | for (HttpRequestResponse requestResponse : requestResponses) { 723 | executorService.submit(() -> { 724 | try { 725 | HttpRequest baseRequest = requestResponse.request(); 726 | 727 | // Remove unwanted headers 728 | for (String header : HEADERS_TO_REMOVE) { 729 | baseRequest = baseRequest.withRemovedHeader(header); 730 | } 731 | 732 | // Process each chunk of 50 parameters 733 | for (List chunk : parameterChunks) { 734 | // Create a new request with the current chunk of parameters 735 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 736 | HttpRequest chunkRequest = baseRequest.withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 737 | .withUpdatedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 738 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 739 | // Add each parameter in the chunk to the request 740 | for (String parameter : chunk) { 741 | chunkRequest = chunkRequest.withAddedParameters(parameter(parameter, persistence.getString(YOUR_PAYLOAD), HttpParameterType.BODY)); 742 | } 743 | 744 | // Send the modified request 745 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 746 | 747 | // Check if the response is valid and add it to the table 748 | if (isCached(modifiedRequestResponse)) { 749 | table.add(modifiedRequestResponse,true); 750 | } else if (isNOTCached(modifiedRequestResponse)) { 751 | table.add(modifiedRequestResponse,false); 752 | } 753 | } 754 | } catch (Exception e) { 755 | api.logging().logToError("Failed to send request: " + e.getMessage()); 756 | } 757 | }); 758 | } 759 | executorService.shutdown(); 760 | } 761 | 762 | private void fuzzBodyJson(ContextMenuEvent event) { 763 | List requestResponses = event.selectedRequestResponses(); 764 | if (requestResponses.isEmpty()) { 765 | return; 766 | } 767 | 768 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 769 | 770 | 771 | List parameters = loadParameters(); // Load parameters from the file 772 | List> parameterChunks = splitIntoChunks(parameters.toArray(new String[0]), persistence.getInteger(YOUR_PARAMETERS_BODY_PER_REQUEST)); 773 | 774 | for (HttpRequestResponse requestResponse : requestResponses) { 775 | executorService.submit(() -> { 776 | try { 777 | HttpRequest baseRequest = requestResponse.request(); 778 | 779 | // Remove unwanted headers 780 | for (String header : HEADERS_TO_REMOVE) { 781 | baseRequest = baseRequest.withRemovedHeader(header); 782 | } 783 | 784 | // Process each chunk of 50 parameters 785 | for (List chunk : parameterChunks) { 786 | // Create a new request with the current chunk of parameters 787 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 788 | HttpRequest chunkRequest = baseRequest.withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 789 | .withUpdatedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 790 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 791 | 792 | // Add each parameter in the chunk to the request 793 | for (String parameter : chunk) { 794 | chunkRequest = chunkRequest.withAddedParameters(parameter(parameter, persistence.getString(YOUR_PAYLOAD), HttpParameterType.JSON)); 795 | } 796 | 797 | // Send the modified request 798 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 799 | 800 | if (isCached(modifiedRequestResponse)) { 801 | table.add(modifiedRequestResponse,true); 802 | } else if (isNOTCached(modifiedRequestResponse)) { 803 | table.add(modifiedRequestResponse,false); 804 | } 805 | } 806 | } catch (Exception e) { 807 | api.logging().logToError("Failed to send request: " + e.getMessage()); 808 | } 809 | }); 810 | } 811 | executorService.shutdown(); 812 | } 813 | 814 | private void fuzzBodyXml(ContextMenuEvent event) { 815 | List requestResponses = event.selectedRequestResponses(); 816 | if (requestResponses.isEmpty()) { 817 | return; 818 | } 819 | 820 | ExecutorService executorService = Executors.newFixedThreadPool(persistence.getInteger(YOUR_THREAD)); 821 | 822 | 823 | List parameters = loadParameters(); // Load parameters from the file 824 | List> parameterChunks = splitIntoChunks(parameters.toArray(new String[0]), persistence.getInteger(YOUR_PARAMETERS_BODY_PER_REQUEST)); 825 | 826 | for (HttpRequestResponse requestResponse : requestResponses) { 827 | executorService.submit(() -> { 828 | try { 829 | HttpRequest baseRequest = requestResponse.request(); 830 | 831 | // Remove unwanted headers 832 | for (String header : HEADERS_TO_REMOVE) { 833 | baseRequest = baseRequest.withRemovedHeader(header); 834 | } 835 | 836 | // Process each chunk of 50 parameters 837 | for (List chunk : parameterChunks) { 838 | // Create a new request with the current chunk of parameters 839 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 840 | HttpRequest chunkRequest = baseRequest.withUpdatedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 841 | .withUpdatedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 842 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber); 843 | 844 | // Add each parameter in the chunk to the request 845 | for (String parameter : chunk) { 846 | chunkRequest = chunkRequest.withAddedParameters(parameter(parameter, persistence.getString(YOUR_PAYLOAD), HttpParameterType.XML)); 847 | } 848 | 849 | // Send the modified request 850 | HttpRequestResponse modifiedRequestResponse = api.http().sendRequest(chunkRequest); 851 | 852 | // Check if the response is valid and add it to the table 853 | if (isCached(modifiedRequestResponse)) { 854 | table.add(modifiedRequestResponse,true); 855 | } else if (isNOTCached(modifiedRequestResponse)) { 856 | table.add(modifiedRequestResponse,false); 857 | } 858 | } 859 | } catch (Exception e) { 860 | api.logging().logToError("Failed to send request: " + e.getMessage()); 861 | } 862 | }); 863 | } 864 | executorService.shutdown(); 865 | } 866 | } -------------------------------------------------------------------------------- /src/main/java/burpsuite/MyTableModel.java: -------------------------------------------------------------------------------- 1 | package burpsuite; 2 | 3 | import burp.api.montoya.MontoyaApi; 4 | import burp.api.montoya.http.message.HttpRequestResponse; 5 | import burp.api.montoya.proxy.http.InterceptedResponse; 6 | import javax.swing.table.AbstractTableModel; 7 | import java.util.*; 8 | 9 | 10 | public class MyTableModel extends AbstractTableModel { 11 | 12 | private final MontoyaApi api; 13 | private final List log; 14 | 15 | private static class LogEntry { 16 | private final Object message; 17 | private final Boolean cache; 18 | 19 | 20 | public LogEntry(Object message, Boolean cache) { 21 | this.message = message; 22 | this.cache = cache; 23 | 24 | } 25 | public Object getMessage() { 26 | return message; 27 | } 28 | 29 | public boolean isHttpRequestResponse() { 30 | return message instanceof HttpRequestResponse; 31 | } 32 | 33 | public boolean isInterceptedResponse() { 34 | return message instanceof InterceptedResponse; 35 | } 36 | 37 | 38 | public Boolean getCache() { 39 | return cache; 40 | } 41 | } 42 | 43 | public MyTableModel(MontoyaApi api) { 44 | this.api = api; 45 | this.log = new ArrayList<>(); // Initialize the list 46 | } 47 | 48 | @Override 49 | public synchronized int getRowCount() { 50 | return log.size(); // Return the size of the list 51 | } 52 | 53 | @Override 54 | public int getColumnCount() { 55 | return 4; 56 | } 57 | 58 | @Override 59 | public String getColumnName(int column) { 60 | return switch (column) { 61 | case 0 -> "#"; 62 | case 1 -> "Host"; 63 | case 2 -> "Cache"; 64 | case 3 -> "Path"; 65 | default -> ""; 66 | }; 67 | } 68 | 69 | @Override 70 | public synchronized Object getValueAt(int rowIndex, int columnIndex) { 71 | LogEntry entry = log.get(rowIndex); 72 | 73 | switch (columnIndex) { 74 | case 0: 75 | return rowIndex + 1; 76 | case 1: 77 | if (entry.isHttpRequestResponse()) { 78 | HttpRequestResponse httpRequestResponse = (HttpRequestResponse) (entry.getMessage()); 79 | return httpRequestResponse.request().headerValue("Host"); 80 | } else if (entry.isInterceptedResponse()) { 81 | InterceptedResponse interceptedResponse = (InterceptedResponse) (entry.getMessage()); 82 | return interceptedResponse.request().headerValue("Host"); 83 | } else { 84 | return ""; 85 | } 86 | 87 | case 2: 88 | if (entry.getCache()) { 89 | return "Yes"; 90 | } else { 91 | return "No"; 92 | } 93 | case 3: 94 | if (entry.isHttpRequestResponse()) { 95 | HttpRequestResponse httpRequestResponse = (HttpRequestResponse) (entry.getMessage()); 96 | return httpRequestResponse.request().pathWithoutQuery(); 97 | } else if (entry.isInterceptedResponse()) { 98 | InterceptedResponse interceptedResponse = (InterceptedResponse) (entry.getMessage()); 99 | return interceptedResponse.request().pathWithoutQuery(); 100 | } else { 101 | return ""; 102 | } 103 | default: 104 | return ""; 105 | } 106 | } 107 | 108 | public synchronized void add(Object message,Boolean cache) { 109 | LogEntry entry = new LogEntry(message,cache); 110 | log.add(entry); 111 | int index = log.size() - 1; 112 | fireTableRowsInserted(index, index); 113 | } 114 | 115 | public synchronized Object get(int rowIndex) { 116 | LogEntry entry = log.get(rowIndex); 117 | return entry.getMessage(); 118 | } 119 | } -------------------------------------------------------------------------------- /src/main/java/burpsuite/Settings.java: -------------------------------------------------------------------------------- 1 | package burpsuite; 2 | 3 | import burp.api.montoya.persistence.PersistedObject; 4 | 5 | import javax.swing.*; 6 | import java.awt.*; 7 | import java.awt.event.ActionEvent; 8 | import java.awt.event.ActionListener; 9 | 10 | import static burpsuite.UnkeyInput.*; 11 | 12 | public class Settings extends JPanel { 13 | 14 | PersistedObject persistence; 15 | public Settings(PersistedObject persist) { 16 | 17 | this.persistence = persist; 18 | // Set the layout to GridBagLayout for precise control 19 | this.setLayout(new GridBagLayout()); 20 | GridBagConstraints gbc = new GridBagConstraints(); 21 | gbc.fill = GridBagConstraints.HORIZONTAL; 22 | gbc.anchor = GridBagConstraints.NORTHWEST; 23 | gbc.insets = new Insets(20, 5, 1, 5); 24 | 25 | // First row: Description Label 26 | String payloadDescription = "Enter your payload to use :"; 27 | JLabel payloadDescriptionLabel = new JLabel(payloadDescription); 28 | gbc.gridx = 0; // Column 0 29 | gbc.gridy = 0; // Row 0 30 | gbc.gridwidth = 3; // Span across 3 columns 31 | gbc.anchor = GridBagConstraints.WEST; // Align to the left 32 | this.add(payloadDescriptionLabel, gbc); 33 | 34 | // First row: Label, TextField, Button 35 | JLabel label1 = new JLabel("Payload : "); 36 | JTextField payloadInput = new JTextField(persistence.getString(YOUR_PAYLOAD), 30); // Smaller width 37 | JButton saveBtn1 = new JButton("Save"); 38 | 39 | // Add ActionListener to the first button 40 | saveBtn1.addActionListener(new ActionListener() { 41 | @Override 42 | public void actionPerformed(ActionEvent e) { 43 | String payload = payloadInput.getText(); 44 | if (payload.isEmpty()) { 45 | JOptionPane.showMessageDialog(Settings.this, "Payload cannot be empty", "Unkey Input", JOptionPane.ERROR_MESSAGE); 46 | } else { 47 | persistence.setString(YOUR_PAYLOAD, payload); 48 | JOptionPane.showMessageDialog(Settings.this, payload + " saved", "Unkey Input", JOptionPane.INFORMATION_MESSAGE); 49 | } 50 | } 51 | }); 52 | 53 | // Add components of the first row 54 | gbc.gridx = 0; // Column 0 55 | gbc.gridy = 1; // Row 1 56 | gbc.gridwidth = 1; // Reset gridwidth 57 | this.add(label1, gbc); 58 | 59 | gbc.gridx = 1; // Column 1 60 | gbc.gridy = 1; // Row 1 61 | this.add(payloadInput, gbc); 62 | 63 | gbc.gridx = 2; // Column 2 64 | gbc.gridy = 1; // Row 1 65 | this.add(saveBtn1, gbc); 66 | 67 | // Second row: Description Label 68 | String matchDescription = "Enter your match :"; 69 | JLabel timeoutDescriptionLabel = new JLabel(matchDescription); 70 | gbc.gridx = 0; // Column 0 71 | gbc.gridy = 2; // Row 2 72 | gbc.gridwidth = 3; // Span across 3 columns 73 | this.add(timeoutDescriptionLabel, gbc); 74 | 75 | // Second row: Label, TextField, Button 76 | JLabel label2 = new JLabel("Match : "); 77 | JTextField matchInput = new JTextField(persistence.getString(YOUR_MATCH), 30); // Smaller width 78 | JButton saveBtn2 = new JButton("Save"); 79 | 80 | // Add ActionListener to the second button 81 | saveBtn2.addActionListener(new ActionListener() { 82 | @Override 83 | public void actionPerformed(ActionEvent e) { 84 | String match = matchInput.getText(); 85 | if (match.isEmpty()) { 86 | JOptionPane.showMessageDialog(Settings.this, "Match cannot be empty", "Unkey Input", JOptionPane.ERROR_MESSAGE); 87 | } else { 88 | persistence.setString(YOUR_MATCH, match); 89 | JOptionPane.showMessageDialog(Settings.this, match + " saved", "Unkey Input", JOptionPane.INFORMATION_MESSAGE); 90 | } 91 | } 92 | }); 93 | 94 | // Add components of the second row 95 | gbc.gridx = 0; // Column 0 96 | gbc.gridy = 3; // Row 3 97 | gbc.gridwidth = 1; // Reset gridwidth 98 | this.add(label2, gbc); 99 | 100 | gbc.gridx = 1; // Column 1 101 | gbc.gridy = 3; // Row 3 102 | this.add(matchInput, gbc); 103 | 104 | gbc.gridx = 2; // Column 2 105 | gbc.gridy = 3; // Row 3 106 | this.add(saveBtn2, gbc); 107 | 108 | // Third row: Description Label 109 | String thredsDescription = "Set number of threads :"; 110 | JLabel thredsDescriptionLabel = new JLabel(thredsDescription); 111 | gbc.gridx = 0; // Column 0 112 | gbc.gridy = 4; // Row 4 113 | gbc.gridwidth = 3; // Span across 3 columns 114 | this.add(thredsDescriptionLabel, gbc); 115 | 116 | // Third row: Label, TextField, Button 117 | JLabel label3 = new JLabel("Threads : "); 118 | JTextField thredsInput = new JTextField(Integer.toString(persistence.getInteger(YOUR_THREAD)), 30); // Smaller width 119 | JButton saveBtn3 = new JButton("Save"); 120 | 121 | // Add ActionListener to the third button 122 | saveBtn3.addActionListener(new ActionListener() { 123 | @Override 124 | public void actionPerformed(ActionEvent e) { 125 | String threads = thredsInput.getText(); 126 | if (threads.isEmpty()) { 127 | JOptionPane.showMessageDialog(Settings.this, "Threads cannot be empty", "Unkey Input", JOptionPane.ERROR_MESSAGE); 128 | } else { 129 | persistence.setInteger(YOUR_THREAD, Integer.parseInt(threads)); 130 | JOptionPane.showMessageDialog(Settings.this, threads + " saved", "Unkey Input", JOptionPane.INFORMATION_MESSAGE); 131 | } 132 | } 133 | }); 134 | 135 | // Add components of the third row 136 | gbc.gridx = 0; // Column 0 137 | gbc.gridy = 5; // Row 5 138 | gbc.gridwidth = 1; // Reset gridwidth 139 | this.add(label3, gbc); 140 | 141 | gbc.gridx = 1; // Column 1 142 | gbc.gridy = 5; // Row 5 143 | this.add(thredsInput, gbc); 144 | 145 | gbc.gridx = 2; // Column 2 146 | gbc.gridy = 5; // Row 5 147 | this.add(saveBtn3, gbc); 148 | 149 | // Fourth row: Description Label 150 | String headersDescription = "Set number of headers per request :"; 151 | JLabel headersDescriptionLabel = new JLabel(headersDescription); 152 | gbc.gridx = 0; // Column 0 153 | gbc.gridy = 6; // Row 6 154 | gbc.gridwidth = 3; // Span across 3 columns 155 | this.add(headersDescriptionLabel, gbc); 156 | 157 | // Fourth row: Label, TextField, Button 158 | JLabel label4 = new JLabel("Headers : "); 159 | JTextField headersInput = new JTextField(Integer.toString(persistence.getInteger(YOUR_HEADERS_PER_REQUEST)), 30); // Smaller width 160 | JButton saveBtn4 = new JButton("Save"); 161 | 162 | // Add ActionListener to the fourth button 163 | saveBtn4.addActionListener(new ActionListener() { 164 | @Override 165 | public void actionPerformed(ActionEvent e) { 166 | String header = headersInput.getText(); 167 | 168 | if (header.isEmpty()) { 169 | JOptionPane.showMessageDialog(Settings.this, "Number of headers cannot be empty", "Unkey Input", JOptionPane.ERROR_MESSAGE); 170 | } else { 171 | persistence.setInteger(YOUR_HEADERS_PER_REQUEST, Integer.parseInt(header)); 172 | JOptionPane.showMessageDialog(Settings.this, header + " saved", "Unkey Input", JOptionPane.INFORMATION_MESSAGE); 173 | } 174 | } 175 | }); 176 | 177 | // Add components of the fourth row 178 | gbc.gridx = 0; // Column 0 179 | gbc.gridy = 7; // Row 7 180 | gbc.gridwidth = 1; // Reset gridwidth 181 | this.add(label4, gbc); 182 | 183 | gbc.gridx = 1; // Column 1 184 | gbc.gridy = 7; // Row 7 185 | this.add(headersInput, gbc); 186 | 187 | gbc.gridx = 2; // Column 2 188 | gbc.gridy = 7; // Row 7 189 | this.add(saveBtn4, gbc); 190 | 191 | // Fifth row: Description Label 192 | String queryDescription = "Set number of query parameters per request :"; 193 | JLabel queryDescriptionLabel = new JLabel(queryDescription); 194 | gbc.gridx = 0; // Column 0 195 | gbc.gridy = 8; // Row 8 196 | gbc.gridwidth = 3; // Span across 3 columns 197 | this.add(queryDescriptionLabel, gbc); 198 | 199 | // Fifth row: Label, TextField, Button 200 | JLabel label5 = new JLabel("Query : "); 201 | JTextField queryInput = new JTextField(Integer.toString(persistence.getInteger(YOUR_PARAMETERS_QUERY_PER_REQUEST)), 30); // Wider width for User-Agent 202 | JButton saveBtn5 = new JButton("Save"); 203 | 204 | // Add ActionListener to the fifth button 205 | saveBtn5.addActionListener(new ActionListener() { 206 | @Override 207 | public void actionPerformed(ActionEvent e) { 208 | String query = queryInput.getText(); 209 | 210 | if (query.isEmpty()) { 211 | JOptionPane.showMessageDialog(Settings.this, "Number of query parameters cannot be empty", "Unkey Input", JOptionPane.ERROR_MESSAGE); 212 | } else { 213 | persistence.setInteger(YOUR_PARAMETERS_QUERY_PER_REQUEST, Integer.parseInt(query)); 214 | JOptionPane.showMessageDialog(Settings.this, query + " saved", "Unkey Input", JOptionPane.INFORMATION_MESSAGE); 215 | } 216 | } 217 | }); 218 | 219 | // Add components of the fifth row 220 | gbc.gridx = 0; // Column 0 221 | gbc.gridy = 9; // Row 9 222 | gbc.gridwidth = 1; // Reset gridwidth 223 | this.add(label5, gbc); 224 | 225 | gbc.gridx = 1; // Column 1 226 | gbc.gridy = 9; // Row 9 227 | this.add(queryInput, gbc); 228 | 229 | gbc.gridx = 2; // Column 2 230 | gbc.gridy = 9; // Row 9 231 | this.add(saveBtn5, gbc); 232 | 233 | // Sixth row: Description Label 234 | String cookieDescription = "Set number of cookie parameters per request :"; 235 | JLabel cookieDescriptionLabel = new JLabel(cookieDescription); 236 | gbc.gridx = 0; // Column 0 237 | gbc.gridy = 10; // Row 10 238 | gbc.gridwidth = 3; // Span across 3 columns 239 | this.add(cookieDescriptionLabel, gbc); 240 | 241 | // Sixth row: Label, TextField, Button 242 | JLabel label6 = new JLabel("Cookie : "); 243 | JTextField cookieInput = new JTextField(Integer.toString(persistence.getInteger(YOUR_PARAMETERS_COOKIE_PER_REQUEST)), 30); // Wider width for proxy address 244 | JButton saveBtn6 = new JButton("Save"); 245 | 246 | // Add ActionListener to the sixth button 247 | saveBtn6.addActionListener(new ActionListener() { 248 | @Override 249 | public void actionPerformed(ActionEvent e) { 250 | String cookie = cookieInput.getText(); 251 | if (cookie.isEmpty()) { 252 | JOptionPane.showMessageDialog(Settings.this, "Number of cookie parameters cannot be empty", "Unkey Input", JOptionPane.ERROR_MESSAGE); 253 | } else { 254 | persistence.setInteger(YOUR_PARAMETERS_COOKIE_PER_REQUEST, Integer.parseInt(cookie)); 255 | JOptionPane.showMessageDialog(Settings.this, cookie + " saved", "Unkey Input", JOptionPane.INFORMATION_MESSAGE); 256 | } 257 | } 258 | }); 259 | 260 | // Add components of the sixth row 261 | gbc.gridx = 0; // Column 0 262 | gbc.gridy = 11; // Row 11 263 | gbc.gridwidth = 1; // Reset gridwidth 264 | this.add(label6, gbc); 265 | 266 | gbc.gridx = 1; // Column 1 267 | gbc.gridy = 11; // Row 11 268 | this.add(cookieInput, gbc); 269 | 270 | gbc.gridx = 2; // Column 2 271 | gbc.gridy = 11; // Row 11 272 | this.add(saveBtn6, gbc); 273 | 274 | // Seventh row: Description Label 275 | String bodyDescription = "Set number of body parameters per request :"; 276 | JLabel bodyDescriptionLabel = new JLabel(bodyDescription); 277 | gbc.gridx = 0; // Column 0 278 | gbc.gridy = 12; // Row 12 279 | gbc.gridwidth = 3; // Span across 3 columns 280 | this.add(bodyDescriptionLabel, gbc); 281 | 282 | // Seventh row: Label, TextField, Button 283 | JLabel label7 = new JLabel("Body : "); 284 | JTextField bodyInput = new JTextField(Integer.toString(persistence.getInteger(YOUR_PARAMETERS_BODY_PER_REQUEST)), 30); // Wider width for cookie 285 | JButton saveBtn7 = new JButton("Save"); 286 | 287 | // Add ActionListener to the seventh button 288 | saveBtn7.addActionListener(new ActionListener() { 289 | @Override 290 | public void actionPerformed(ActionEvent e) { 291 | String body = bodyInput.getText(); 292 | if (body.isEmpty()) { 293 | JOptionPane.showMessageDialog(Settings.this, "Number of body parameters cannot be empty", "Unkey Input", JOptionPane.ERROR_MESSAGE); 294 | } else { 295 | persistence.setInteger(YOUR_PARAMETERS_BODY_PER_REQUEST, Integer.parseInt(body)); 296 | JOptionPane.showMessageDialog(Settings.this, body + " saved", "Unkey Input", JOptionPane.INFORMATION_MESSAGE); 297 | } 298 | } 299 | }); 300 | 301 | gbc.gridx = 0; // Column 0 302 | gbc.gridy = 13; // Row 13 303 | gbc.gridwidth = 1; // Reset gridwidth 304 | this.add(label7, gbc); 305 | 306 | gbc.gridx = 1; // Column 1 307 | gbc.gridy = 13; // Row 13 308 | this.add(bodyInput, gbc); 309 | 310 | gbc.gridx = 2; // Column 2 311 | gbc.gridy = 13; // Row 13 312 | this.add(saveBtn7, gbc); 313 | } 314 | } -------------------------------------------------------------------------------- /src/main/java/burpsuite/UnkeyInput.java: -------------------------------------------------------------------------------- 1 | package burpsuite; 2 | 3 | import burp.api.montoya.BurpExtension; 4 | import burp.api.montoya.MontoyaApi; 5 | import burp.api.montoya.http.message.HttpRequestResponse; 6 | import burp.api.montoya.persistence.PersistedObject; 7 | import burp.api.montoya.proxy.http.InterceptedResponse; 8 | import burp.api.montoya.ui.UserInterface; 9 | import burp.api.montoya.ui.editor.HttpRequestEditor; 10 | import burp.api.montoya.ui.editor.HttpResponseEditor; 11 | import javax.swing.*; 12 | import javax.swing.table.DefaultTableCellRenderer; 13 | import javax.swing.table.TableColumn; 14 | import javax.swing.table.TableModel; 15 | import javax.swing.table.TableRowSorter; 16 | import java.awt.*; 17 | import java.awt.event.ActionEvent; 18 | import java.awt.event.InputEvent; 19 | import java.awt.event.KeyEvent; 20 | import java.time.LocalDateTime; 21 | import java.time.format.DateTimeFormatter; 22 | import java.util.Comparator; 23 | import java.util.Locale; 24 | import static burp.api.montoya.ui.editor.EditorOptions.READ_ONLY; 25 | 26 | public class UnkeyInput implements BurpExtension { 27 | 28 | private MontoyaApi api; 29 | DateTimeFormatter dateTimeFormatter; 30 | 31 | static final String YOUR_PAYLOAD = "YOUR_PAYLOAD"; 32 | static final String YOUR_MATCH = "YOUR_MATCH"; 33 | static final String YOUR_THREAD = "YOUR_THREAD"; 34 | static final String YOUR_HEADERS_PER_REQUEST = "YOUR_HEADERS_PER_REQUEST"; 35 | static final String YOUR_PARAMETERS_QUERY_PER_REQUEST = "YOUR_PARAMETERS_QUERY_PER_REQUEST"; 36 | static final String YOUR_PARAMETERS_BODY_PER_REQUEST = "YOUR_PARAMETERS_BODY_PER_REQUEST"; 37 | static final String YOUR_PARAMETERS_COOKIE_PER_REQUEST = "YOUR_PARAMETERS_COOKIE_PER_REQUEST"; 38 | 39 | 40 | 41 | @Override 42 | public void initialize(MontoyaApi montoyaApi) { 43 | this.api = montoyaApi; 44 | this.dateTimeFormatter = DateTimeFormatter.ofPattern("d MMM yyyy", Locale.ENGLISH); 45 | 46 | PersistedObject persist = api.persistence().extensionData(); 47 | 48 | String PAYLOAD = persist.getString(YOUR_PAYLOAD); 49 | if (PAYLOAD == null) { 50 | PAYLOAD = "%3Cxss%3E%253Cxss%253E\\u003Cxss\\u003E"; 51 | } 52 | persist.setString(YOUR_PAYLOAD, PAYLOAD); 53 | 54 | String MATCH = persist.getString(YOUR_MATCH); 55 | if (MATCH == null) { 56 | MATCH = ""; 57 | } 58 | persist.setString(YOUR_MATCH, MATCH); 59 | 60 | Integer THREAD = persist.getInteger(YOUR_THREAD); 61 | if (THREAD == null) { 62 | THREAD = 50; 63 | } 64 | persist.setInteger(YOUR_THREAD, THREAD); 65 | 66 | Integer HEADERS = persist.getInteger(YOUR_HEADERS_PER_REQUEST); 67 | if (HEADERS == null) { 68 | HEADERS = 100; 69 | } 70 | persist.setInteger(YOUR_HEADERS_PER_REQUEST, HEADERS); 71 | 72 | Integer QUERY = persist.getInteger(YOUR_PARAMETERS_QUERY_PER_REQUEST); 73 | if (QUERY == null) { 74 | QUERY = 30; 75 | } 76 | persist.setInteger(YOUR_PARAMETERS_QUERY_PER_REQUEST, QUERY); 77 | 78 | Integer BODY = persist.getInteger(YOUR_PARAMETERS_BODY_PER_REQUEST); 79 | if (BODY == null) { 80 | BODY = 60; 81 | } 82 | persist.setInteger(YOUR_PARAMETERS_BODY_PER_REQUEST, BODY); 83 | 84 | 85 | Integer COOKIE = persist.getInteger(YOUR_PARAMETERS_COOKIE_PER_REQUEST); 86 | if (COOKIE == null) { 87 | COOKIE = 45; 88 | } 89 | persist.setInteger(YOUR_PARAMETERS_COOKIE_PER_REQUEST, COOKIE); 90 | 91 | 92 | api.extension().setName("Unkey Input"); 93 | MyTableModel table = new MyTableModel(api); 94 | api.userInterface().registerSuiteTab("Unkey Input", LoggerTab(table,persist)); 95 | api.proxy().registerRequestHandler(new proxyHandler(table,persist)); 96 | api.proxy().registerResponseHandler(new proxyHandler(table,persist)); 97 | api.userInterface().registerContextMenuItemsProvider(new MenuItemsProvider(api,table,persist)); 98 | } 99 | 100 | private Component LoggerTab(MyTableModel table, PersistedObject persist) { 101 | 102 | JTabbedPane responseCacheableGUI = new JTabbedPane(); 103 | 104 | JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 105 | UserInterface userInterface = api.userInterface(); 106 | HttpRequestEditor requestViewer = userInterface.createHttpRequestEditor(READ_ONLY); 107 | HttpResponseEditor responseViewer = userInterface.createHttpResponseEditor(READ_ONLY); 108 | 109 | JTabbedPane requestTab = new JTabbedPane(); 110 | requestTab.addTab("Request", requestViewer.uiComponent()); 111 | 112 | JTabbedPane responseTab = new JTabbedPane(); 113 | responseTab.addTab("Response", responseViewer.uiComponent()); 114 | 115 | JSplitPane splitTabs = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); 116 | 117 | splitTabs.setLeftComponent(requestTab); 118 | splitTabs.setRightComponent(responseTab); 119 | 120 | splitPane.setRightComponent(splitTabs); 121 | 122 | JTable jTable = new JTable(table) { 123 | @Override 124 | public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { 125 | super.changeSelection(rowIndex, columnIndex, toggle, extend); 126 | Object message = table.get(convertRowIndexToModel(rowIndex)); 127 | if (message instanceof InterceptedResponse) { 128 | InterceptedResponse interceptedResponseMessage = (InterceptedResponse) message; 129 | requestViewer.setRequest(interceptedResponseMessage.request()); 130 | responseViewer.setResponse(interceptedResponseMessage); 131 | 132 | } else if (message instanceof HttpRequestResponse) { 133 | HttpRequestResponse httpRequestResponseMessage = (HttpRequestResponse) message; 134 | requestViewer.setRequest(httpRequestResponseMessage.request()); 135 | responseViewer.setResponse(httpRequestResponseMessage.response()); 136 | } 137 | } 138 | }; 139 | 140 | jTable.setRowHeight(30); 141 | jTable.setAutoCreateRowSorter(true); 142 | TableRowSorter sorter = new TableRowSorter<>(table); 143 | jTable.setRowSorter(sorter); 144 | sorter.setComparator(0, new Comparator() { 145 | @Override 146 | public int compare(Integer o1, Integer o2) { 147 | return o1.compareTo(o2); // Compare as integers 148 | } 149 | }); 150 | 151 | jTable.getRowSorter().toggleSortOrder(0); 152 | DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer(); 153 | centerRenderer.setHorizontalAlignment(SwingConstants.CENTER); 154 | jTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer); 155 | jTable.getColumnModel().getColumn(2).setCellRenderer(centerRenderer); 156 | 157 | 158 | TableColumn ID = jTable.getColumnModel().getColumn(0); 159 | ID.setMinWidth(50); 160 | ID.setMaxWidth(100); 161 | 162 | TableColumn Host = jTable.getColumnModel().getColumn(1); 163 | Host.setMinWidth(350); 164 | Host.setMaxWidth(700); 165 | 166 | 167 | TableColumn CACHE = jTable.getColumnModel().getColumn(2); 168 | CACHE.setMinWidth(100); 169 | CACHE.setMaxWidth(150); 170 | 171 | JPopupMenu popupMenu = new JPopupMenu(); 172 | JMenuItem sendToRepeaterMenuItem = new JMenuItem("Send to Repeater"); 173 | popupMenu.add(sendToRepeaterMenuItem); 174 | 175 | Action sendToRepeaterAction = new AbstractAction() { 176 | @Override 177 | public void actionPerformed(ActionEvent e) { 178 | int[] selectedRows = jTable.getSelectedRows(); 179 | for (int selectedRow : selectedRows) { 180 | Object message= table.get(jTable.convertRowIndexToModel(selectedRow)); 181 | if (message instanceof InterceptedResponse) { 182 | InterceptedResponse interceptedResponseMessage = (InterceptedResponse) message; 183 | api.repeater().sendToRepeater(interceptedResponseMessage.request(),dateTimeFormatter.format(LocalDateTime.now())); 184 | 185 | } else if (message instanceof HttpRequestResponse) { 186 | HttpRequestResponse httpRequestResponseMessage = (HttpRequestResponse) message; 187 | api.repeater().sendToRepeater(httpRequestResponseMessage.request(),dateTimeFormatter.format(LocalDateTime.now())); 188 | 189 | } 190 | } 191 | } 192 | }; 193 | 194 | sendToRepeaterMenuItem.addActionListener(sendToRepeaterAction); 195 | jTable.setComponentPopupMenu(popupMenu); 196 | 197 | KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK); 198 | jTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(keyStroke, "sendToRepeater"); 199 | jTable.getActionMap().put("sendToRepeater", sendToRepeaterAction); 200 | 201 | JScrollPane scrollPane = new JScrollPane(jTable); 202 | splitPane.setLeftComponent(scrollPane); 203 | 204 | responseCacheableGUI.addTab("Logger",splitPane); 205 | responseCacheableGUI.addTab("Settings",new Settings(persist)); 206 | 207 | return responseCacheableGUI; 208 | } 209 | 210 | } 211 | -------------------------------------------------------------------------------- /src/main/java/burpsuite/proxyHandler.java: -------------------------------------------------------------------------------- 1 | package burpsuite; 2 | 3 | import burp.api.montoya.http.message.StatusCodeClass; 4 | import burp.api.montoya.persistence.PersistedObject; 5 | import burp.api.montoya.proxy.http.*; 6 | import burp.api.montoya.http.message.requests.HttpRequest; 7 | import burp.api.montoya.http.message.responses.HttpResponse; 8 | import java.util.concurrent.ThreadLocalRandom; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import static burp.api.montoya.http.message.params.HttpParameter.cookieParameter; 12 | import static burp.api.montoya.http.message.params.HttpParameter.urlParameter; 13 | import static burpsuite.UnkeyInput.YOUR_MATCH; 14 | import static burpsuite.UnkeyInput.YOUR_PAYLOAD; 15 | 16 | public class proxyHandler implements ProxyRequestHandler, ProxyResponseHandler { 17 | 18 | private final MyTableModel table; 19 | PersistedObject persistence; 20 | public proxyHandler(MyTableModel table, PersistedObject persist) { 21 | this.table = table; 22 | this.persistence = persist; 23 | 24 | } 25 | 26 | private HttpRequest addCustomHeaders(HttpRequest request) { 27 | Map customHeaders = new HashMap<>(); 28 | customHeaders.put("Referer", "Referer-" + persistence.getString(YOUR_PAYLOAD)); 29 | customHeaders.put("Akamai-Client-Ip", "Akamai-Client-Ip-" + persistence.getString(YOUR_PAYLOAD)); 30 | customHeaders.put("Cf-Connecting-Ip", "Cf-Connecting-Ip-" + persistence.getString(YOUR_PAYLOAD)); 31 | customHeaders.put("Client-Ip", "Client-Ip-" + persistence.getString(YOUR_PAYLOAD)); 32 | customHeaders.put("Fastly-Client-Ip", "Fastly-Client-Ip-" + persistence.getString(YOUR_PAYLOAD)); 33 | customHeaders.put("Forwarded", "Forwarded-" + persistence.getString(YOUR_PAYLOAD)); 34 | customHeaders.put("True-Client-Ip", "True-Client-Ip-" + persistence.getString(YOUR_PAYLOAD)); 35 | customHeaders.put("X-Client-Ip", "X-Client-Ip-" + persistence.getString(YOUR_PAYLOAD)); 36 | customHeaders.put("X-Cluster-Client-Ip", "X-Cluster-Client-Ip-" + persistence.getString(YOUR_PAYLOAD)); 37 | customHeaders.put("X-Forwarded-By", "X-Forwarded-By-" + persistence.getString(YOUR_PAYLOAD)); 38 | customHeaders.put("X-Forwarded-Client-Ip", "X-Forwarded-Client-Ip-" + persistence.getString(YOUR_PAYLOAD)); 39 | customHeaders.put("X-Forwarded-For", "X-Forwarded-For-" + persistence.getString(YOUR_PAYLOAD)); 40 | customHeaders.put("X-Forwarded-For-Original", "X-Forwarded-For-Original-" + persistence.getString(YOUR_PAYLOAD)); 41 | customHeaders.put("X-Forwarded-Host", "X-Forwarded-Host-" + persistence.getString(YOUR_PAYLOAD)); 42 | customHeaders.put("X-Forwarded-Path", "X-Forwarded-Path-" + persistence.getString(YOUR_PAYLOAD)); 43 | customHeaders.put("X-Forwarded-Server", "X-Forwarded-Server-" + persistence.getString(YOUR_PAYLOAD)); 44 | customHeaders.put("X-Forwarded-Uri", "X-Forwarded-Uri-" + persistence.getString(YOUR_PAYLOAD)); 45 | customHeaders.put("X-Host", "X-Host-" + persistence.getString(YOUR_PAYLOAD)); 46 | customHeaders.put("X-Http-Forwarded-For", "X-Http-Forwarded-For-" + persistence.getString(YOUR_PAYLOAD)); 47 | customHeaders.put("X-Original-Cookie", "X-Original-Cookie-" + persistence.getString(YOUR_PAYLOAD)); 48 | customHeaders.put("X-Original-Forwarded-For", "X-Original-Forwarded-For-" + persistence.getString(YOUR_PAYLOAD)); 49 | customHeaders.put("X-Original-Host", "X-Original-Host-" + persistence.getString(YOUR_PAYLOAD)); 50 | customHeaders.put("X-Original-Referer", "X-Original-Referer-" + persistence.getString(YOUR_PAYLOAD)); 51 | customHeaders.put("X-Original-Url", "X-Original-Url-" + persistence.getString(YOUR_PAYLOAD)); 52 | customHeaders.put("X-Original-User-Agent", "X-Original-User-Agent-" + persistence.getString(YOUR_PAYLOAD)); 53 | customHeaders.put("X-Originating-Host", "X-Originating-Host-" + persistence.getString(YOUR_PAYLOAD)); 54 | customHeaders.put("X-Originating-Ip", "X-Originating-Ip-" + persistence.getString(YOUR_PAYLOAD)); 55 | customHeaders.put("X-Proxyuser-Host", "X-Proxyuser-Host-" + persistence.getString(YOUR_PAYLOAD)); 56 | customHeaders.put("X-Proxyuser-Ip", "X-Proxyuser-Ip-" + persistence.getString(YOUR_PAYLOAD)); 57 | customHeaders.put("X-Proxyuser-Uri", "X-Proxyuser-Uri-" + persistence.getString(YOUR_PAYLOAD)); 58 | customHeaders.put("X-Real-Host", "X-Real-Host-" + persistence.getString(YOUR_PAYLOAD)); 59 | customHeaders.put("X-Real-Ip", "X-Real-Ip-" + persistence.getString(YOUR_PAYLOAD)); 60 | customHeaders.put("X-Remote-Addr", "X-Remote-Addr-" + persistence.getString(YOUR_PAYLOAD)); 61 | customHeaders.put("X-Remote-Ip", "X-Remote-Ip-" + persistence.getString(YOUR_PAYLOAD)); 62 | customHeaders.put("X-Rewrite-Url", "X-Rewrite-Url-" + persistence.getString(YOUR_PAYLOAD)); 63 | customHeaders.put("X-True-Ip", "X-True-Ip-" + persistence.getString(YOUR_PAYLOAD)); 64 | customHeaders.put("X-Wap-Client-Ip", "X-Wap-Client-Ip-" + persistence.getString(YOUR_PAYLOAD)); 65 | customHeaders.put("X-Wap-Network-Client-Ip", "X-Wap-Network-Client-Ip-" + persistence.getString(YOUR_PAYLOAD)); 66 | customHeaders.put("X-Wap-Profile", "X-Wap-Profile-" + persistence.getString(YOUR_PAYLOAD)); 67 | 68 | for (Map.Entry entry : customHeaders.entrySet()) { 69 | request = request.withHeader(entry.getKey(), entry.getValue()); 70 | } 71 | 72 | return request; 73 | } 74 | 75 | 76 | private boolean hasCacheHeaders(HttpResponse response) { 77 | String[] cacheHeaders = {"Age", "CDN-Cache", "CF-Cache-Status", "Server-Timing", "X-Cache", "X-Cache-Info", "X-Cache-Remote", "X-Check-Cacheable", "X-Drupal-Cache", "X-Drupal-Dynamic-Cache", "X-Proxy-Cache", "X-Rack-Cache", "Akamai-Cache-Status"}; 78 | for (String header : cacheHeaders) { 79 | if (response.hasHeader(header)) { 80 | return true; 81 | } 82 | } 83 | return false; 84 | } 85 | 86 | 87 | @Override 88 | public ProxyRequestReceivedAction handleRequestReceived(InterceptedRequest interceptedRequest) { 89 | return ProxyRequestReceivedAction.continueWith(interceptedRequest); 90 | } 91 | 92 | @Override 93 | public ProxyRequestToBeSentAction handleRequestToBeSent(InterceptedRequest interceptedRequest) { 94 | try { 95 | long randomNumber = ThreadLocalRandom.current().nextLong(100_000_000_000L, 1_000_000_000_000L); 96 | HttpRequest modifiedRequest = interceptedRequest 97 | .withAddedParameters(urlParameter("_parameter", String.valueOf(randomNumber))) 98 | .withAddedParameters(cookieParameter("_Cookie",String.valueOf(randomNumber))) 99 | .withRemovedHeader("If-Modified-Since") 100 | .withRemovedHeader("If-None-Match") 101 | .withHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/" + randomNumber + " Safari/" + randomNumber) 102 | .withHeader("Pragma", "akamai-x-check-cacheable,akamai-x-cache-on") 103 | .withHeader("Fastly-Debug", "1"); 104 | 105 | // Add custom headers 106 | modifiedRequest = addCustomHeaders(modifiedRequest); 107 | return ProxyRequestToBeSentAction.continueWith(modifiedRequest); 108 | } catch (Exception e) { 109 | return ProxyRequestToBeSentAction.continueWith(interceptedRequest); 110 | } 111 | } 112 | @Override 113 | public ProxyResponseReceivedAction handleResponseReceived(InterceptedResponse interceptedResponse) { 114 | try { 115 | if (interceptedResponse.body().toString().contains(persistence.getString(YOUR_MATCH)) || interceptedResponse.headers().toString().contains(persistence.getString(YOUR_MATCH))){ 116 | if (hasCacheHeaders(interceptedResponse)) { 117 | table.add(interceptedResponse,true); 118 | } else if (!interceptedResponse.isStatusCodeClass(StatusCodeClass.CLASS_3XX_REDIRECTION)){ 119 | table.add(interceptedResponse,false); 120 | } 121 | } 122 | return ProxyResponseReceivedAction.continueWith(interceptedResponse); 123 | } catch (Exception e) { 124 | return ProxyResponseReceivedAction.continueWith(interceptedResponse); 125 | } 126 | } 127 | 128 | @Override 129 | public ProxyResponseToBeSentAction handleResponseToBeSent(InterceptedResponse interceptedResponse) { 130 | return ProxyResponseToBeSentAction.continueWith(interceptedResponse); 131 | } 132 | } --------------------------------------------------------------------------------