diff --git a/README.md b/README.md index 550630a..42e417f 100644 --- a/README.md +++ b/README.md @@ -85,10 +85,10 @@ Verbose: false ./nomore403 -u https://domain.com/admin ``` -### Verbose Mode + Proxy +### Verbose Mode + Proxy + Specific techniques to use ```bash -./nomore403 -u https://domain.com/admin -x http://127.0.0.1:8080 -v +./nomore403 -u https://domain.com/admin -x http://127.0.0.1:8080 -k headers,http-versions -v ``` ### Parse request from Burp @@ -132,6 +132,7 @@ Flags: -l, --rate-limit Halt requests upon encountering a 429 (rate limit) HTTP status code. -r, --redirect Automatically follow redirects in responses. --request-file string Load request configuration and flags from a specified file. + -k, --technique strings Specify one or more attack techniques to use (e.g., headers,path-case). (default [verbs,verbs-case,headers,endpaths,midpaths,http-versions,path-case]) --timeout int Specify a max timeout time in ms (default 6000) -u, --uri string Specify the target URL for the request. -a, --user-agent string pecify a custom User-Agent string for requests (default: 'nomore403'). diff --git a/cmd/api.go b/cmd/api.go index 1b30030..e641971 100644 --- a/cmd/api.go +++ b/cmd/api.go @@ -114,7 +114,7 @@ func request(method, uri string, headers []header, proxy *url.URL, rateLimit boo } // loadFlagsFromRequestFile parse an HTTP request and configure the necessary flags for an execution -func loadFlagsFromRequestFile(requestFile string, schema bool, verbose bool, redirect bool) { +func loadFlagsFromRequestFile(requestFile string, schema bool, verbose bool, techniques []string, redirect bool) { // Read the content of the request file content, err := os.ReadFile(requestFile) if err != nil { @@ -150,5 +150,5 @@ func loadFlagsFromRequestFile(requestFile string, schema bool, verbose bool, red } httpMethod := req.Method // Assign the extracted values to the corresponding flag variables - requester(uri, proxy, userAgent, reqHeaders, bypassIP, folder, httpMethod, verbose, nobanner, rateLimit, timeout, redirect, randomAgent) + requester(uri, proxy, userAgent, reqHeaders, bypassIP, folder, httpMethod, verbose, technique, nobanner, rateLimit, timeout, redirect, randomAgent) } diff --git a/cmd/requester.go b/cmd/requester.go index 1eaabaf..ecb1cd8 100644 --- a/cmd/requester.go +++ b/cmd/requester.go @@ -36,6 +36,7 @@ type RequestOptions struct { bypassIP string timeout int rateLimit bool + techniques []string verbose bool reqHeaders []string banner bool @@ -110,6 +111,7 @@ func showInfo(options RequestOptions) { fmt.Printf("%s \t%s\n", "Rate Limit detection:", strconv.FormatBool(options.rateLimit)) fmt.Printf("%s \t\t%d\n", "Timeout (ms):", options.timeout) fmt.Printf("%s \t\t%d\n", "Delay (ms):", delay) + fmt.Printf("%s \t\t%s\n", "Techniques:", strings.Join(options.techniques, ", ")) fmt.Printf("%s \t\t%t\n", "Verbose:", options.verbose) } @@ -538,7 +540,7 @@ func randomLine(filePath string) (string, error) { } // requester is the main function that runs all the tests. -func requester(uri string, proxy string, userAgent string, reqHeaders []string, bypassIP string, folder string, method string, verbose bool, banner bool, rateLimit bool, timeout int, redirect bool, randomAgent bool) { +func requester(uri string, proxy string, userAgent string, reqHeaders []string, bypassIP string, folder string, method string, verbose bool, techniques []string, banner bool, rateLimit bool, timeout int, redirect bool, randomAgent bool) { // Set up proxy if provided. if len(proxy) != 0 { if !strings.Contains(proxy, "http") { @@ -599,18 +601,33 @@ func requester(uri string, proxy string, userAgent string, reqHeaders []string, timeout: timeout, rateLimit: rateLimit, verbose: verbose, + techniques: techniques, reqHeaders: reqHeaders, banner: banner, } // Call each function that will send HTTP requests with different variations of headers and URLs. showInfo(options) - requestDefault(options) - requestMethods(options) - requestMethodsCaseSwitching(options) - requestHeaders(options) - requestEndPaths(options) - requestMidPaths(options) - requestHttpVersions(options) - requestPathCaseSwitching(options) + + for _, tech := range techniques { + switch tech { + case "verbs": + requestMethods(options) + case "verbs-case": + requestMethodsCaseSwitching(options) + case "headers": + requestHeaders(options) + case "endpaths": + requestEndPaths(options) + case "midpaths": + requestMidPaths(options) + case "http-versions": + requestHttpVersions(options) + case "path-case": + requestPathCaseSwitching(options) + default: + fmt.Printf("Unrecognized technique. %s\n", tech) + fmt.Print("Available techniques: verbs, verbs-case, headers, endpaths, midpaths, http-versions, path-case\n") + } + } } diff --git a/cmd/root.go b/cmd/root.go index 2658658..27d725b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -27,6 +27,7 @@ var ( reqHeaders []string requestFile string schema bool + technique []string uri string userAgent string verbose bool @@ -54,11 +55,11 @@ var rootCmd = &cobra.Command{ if uri == lastchar { break } - requester(uri, proxy, userAgent, reqHeaders, bypassIP, folder, httpMethod, verbose, nobanner, rateLimit, timeout, redirect, randomAgent) + requester(uri, proxy, userAgent, reqHeaders, bypassIP, folder, httpMethod, verbose, technique, nobanner, rateLimit, timeout, redirect, randomAgent) } } else { if len(requestFile) > 0 { - loadFlagsFromRequestFile(requestFile, schema, verbose, redirect) + loadFlagsFromRequestFile(requestFile, schema, verbose, technique, redirect) } else { if len(uri) == 0 { err := cmd.Help() @@ -67,7 +68,7 @@ var rootCmd = &cobra.Command{ } log.Fatal() } - requester(uri, proxy, userAgent, reqHeaders, bypassIP, folder, httpMethod, verbose, nobanner, rateLimit, timeout, redirect, randomAgent) + requester(uri, proxy, userAgent, reqHeaders, bypassIP, folder, httpMethod, verbose, technique, nobanner, rateLimit, timeout, redirect, randomAgent) } } }, @@ -90,11 +91,12 @@ func init() { rootCmd.PersistentFlags().StringVarP(&httpMethod, "http-method", "t", "", "Specify the HTTP method for the request (e.g., GET, POST). Default is 'GET'.") rootCmd.PersistentFlags().IntVarP(&maxGoroutines, "max-goroutines", "m", 50, "Limit the maximum number of concurrent goroutines to manage load (default: 50).") rootCmd.PersistentFlags().BoolVarP(&nobanner, "no-banner", "", false, "Disable the display of the startup banner (default: banner shown).") - rootCmd.PersistentFlags().StringVarP(&proxy, "proxy", "x", "", "Specify a proxy server for requests, e.g., 'http://server:port'.") + rootCmd.PersistentFlags().StringVarP(&proxy, "proxy", "x", "", "Specify a proxy server for requests (e.g., 'http://server:port').") rootCmd.PersistentFlags().BoolVarP(&randomAgent, "random-agent", "", false, "Enable the use of a randomly selected User-Agent.") rootCmd.PersistentFlags().BoolVarP(&rateLimit, "rate-limit", "l", false, "Halt requests upon encountering a 429 (rate limit) HTTP status code.") rootCmd.PersistentFlags().BoolVarP(&redirect, "redirect", "r", false, "Automatically follow redirects in responses.") rootCmd.PersistentFlags().StringVarP(&requestFile, "request-file", "", "", "Load request configuration and flags from a specified file.") + rootCmd.PersistentFlags().StringSliceVarP(&technique, "technique", "k", []string{"verbs", "verbs-case", "headers", "endpaths", "midpaths", "http-versions", "path-case"}, "Specify one or more attack techniques to use (e.g., headers,path-case).") rootCmd.PersistentFlags().IntVarP(&timeout, "timeout", "", 6000, "Specify a max timeout time in ms.") rootCmd.PersistentFlags().StringVarP(&uri, "uri", "u", "", "Specify the target URL for the request.") rootCmd.PersistentFlags().StringVarP(&userAgent, "user-agent", "a", "", "pecify a custom User-Agent string for requests (default: 'nomore403').")