diff --git a/.gitignore b/.gitignore index 55123f6..876c01e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,5 +15,8 @@ # Test requests files request.txt +# Security Notes +.security-notes.json + # Built binary dontgo403 diff --git a/cmd/requester.go b/cmd/requester.go index f97ff2c..1c195aa 100644 --- a/cmd/requester.go +++ b/cmd/requester.go @@ -5,6 +5,7 @@ import ( "net/url" "strconv" "strings" + "sync" "time" "unicode" @@ -22,36 +23,36 @@ type Result struct { var _verbose bool var default_sc int var default_cl int +var printMutex = &sync.Mutex{} // printResponse prints the results of HTTP requests in a tabular format with colored output based on the status codes. -func printResponse(results []Result) { +func printResponse(result Result) { + printMutex.Lock() + defer printMutex.Unlock() + t := tabby.New() var code string - for _, result := range results { - switch result.statusCode { - case 200, 201, 202, 203, 204, 205, 206: - code = color.GreenString(strconv.Itoa(result.statusCode)) - case 300, 301, 302, 303, 304, 307, 308: - code = color.YellowString(strconv.Itoa(result.statusCode)) - case 400, 401, 402, 403, 404, 405, 406, 407, 408, 413, 429: - code = color.RedString(strconv.Itoa(result.statusCode)) - case 500, 501, 502, 503, 504, 505, 511: - code = color.MagentaString(strconv.Itoa(result.statusCode)) - } - if _verbose != true { - if default_sc == result.statusCode { - continue - } else { - t.AddLine(code, color.BlueString(strconv.Itoa(result.contentLength)+" bytes"), result.line) - } + switch result.statusCode { + case 200, 201, 202, 203, 204, 205, 206: + code = color.GreenString(strconv.Itoa(result.statusCode)) + case 300, 301, 302, 303, 304, 307, 308: + code = color.YellowString(strconv.Itoa(result.statusCode)) + case 400, 401, 402, 403, 404, 405, 406, 407, 408, 413, 429: + code = color.RedString(strconv.Itoa(result.statusCode)) + case 500, 501, 502, 503, 504, 505, 511: + code = color.MagentaString(strconv.Itoa(result.statusCode)) + } + if _verbose != true { + if default_sc == result.statusCode || result.contentLength == 0 || result.statusCode == 404 { + return } else { t.AddLine(code, color.BlueString(strconv.Itoa(result.contentLength)+" bytes"), result.line) } - + } else { + t.AddLine(code, color.BlueString(strconv.Itoa(result.contentLength)+" bytes"), result.line) } t.Print() - } // requestDefault makes HTTP request to check the default response @@ -66,7 +67,7 @@ func requestDefault(uri string, headers []header, proxy *url.URL, method string) } results = append(results, Result{method, statusCode, len(response)}) - printResponse(results) + printResponse(Result{uri, statusCode, len(response)}) for _, result := range results { default_sc = result.statusCode default_cl = result.contentLength @@ -85,8 +86,6 @@ func requestMethods(uri string, headers []header, proxy *url.URL, folder string) w := goccm.New(max_goroutines) - results := []Result{} - for _, line := range lines { time.Sleep(time.Duration(delay) * time.Millisecond) w.Wait() @@ -96,12 +95,11 @@ func requestMethods(uri string, headers []header, proxy *url.URL, folder string) log.Println(err) } - results = append(results, Result{line, statusCode, len(response)}) + printResponse(Result{line, statusCode, len(response)}) w.Done() }(line) } w.WaitAllDone() - printResponse(results) } // requestHeaders makes HTTP requests using a list of headers from a file and prints the results. It can also bypass IP address restrictions by specifying a bypass IP address. @@ -131,8 +129,6 @@ func requestHeaders(uri string, headers []header, proxy *url.URL, bypassIp strin w := goccm.New(max_goroutines) - results := []Result{} - for _, ip := range ips { for _, line := range lines { time.Sleep(time.Duration(delay) * time.Millisecond) @@ -146,7 +142,7 @@ func requestHeaders(uri string, headers []header, proxy *url.URL, bypassIp strin log.Println(err) } - results = append(results, Result{line + ": " + ip, statusCode, len(response)}) + printResponse(Result{line, statusCode, len(response)}) w.Done() }(line, ip) } @@ -164,12 +160,11 @@ func requestHeaders(uri string, headers []header, proxy *url.URL, bypassIp strin log.Println(err) } - results = append(results, Result{x[0] + ": " + x[1], statusCode, len(response)}) + printResponse(Result{line, statusCode, len(response)}) w.Done() }(simpleheader) } w.WaitAllDone() - printResponse(results) } // requestEndPaths makes HTTP requests using a list of custom end paths from a file and prints the results. @@ -184,8 +179,6 @@ func requestEndPaths(uri string, headers []header, proxy *url.URL, folder string w := goccm.New(max_goroutines) - results := []Result{} - for _, line := range lines { time.Sleep(time.Duration(delay) * time.Millisecond) w.Wait() @@ -195,12 +188,12 @@ func requestEndPaths(uri string, headers []header, proxy *url.URL, folder string log.Println(err) } - results = append(results, Result{uri + line, statusCode, len(response)}) + printResponse(Result{uri + line, statusCode, len(response)}) w.Done() }(line) } + w.WaitAllDone() - printResponse(results) } // requestMidPaths makes HTTP requests using a list of custom mid paths from a file and prints the results. @@ -214,41 +207,41 @@ func requestMidPaths(uri string, headers []header, proxy *url.URL, folder string x := strings.Split(uri, "/") var uripath string - if uri[len(uri)-1:] == "/" { - uripath = x[len(x)-2] - } else { - uripath = x[len(x)-1] - } - - baseuri := strings.ReplaceAll(uri, uripath, "") - baseuri = baseuri[:len(baseuri)-1] + parsedURL, err := url.Parse(uri) + if parsedURL.Path != "" && parsedURL.Path != "/" { + if uri[len(uri)-1:] == "/" { + uripath = x[len(x)-2] + } else { + uripath = x[len(x)-1] + } - w := goccm.New(max_goroutines) + baseuri := strings.ReplaceAll(uri, uripath, "") + baseuri = baseuri[:len(baseuri)-1] - results := []Result{} + w := goccm.New(max_goroutines) - for _, line := range lines { - time.Sleep(time.Duration(delay) * time.Millisecond) - w.Wait() - go func(line string) { - var fullpath string - if uri[len(uri)-1:] == "/" { - fullpath = baseuri + line + uripath + "/" - } else { - fullpath = baseuri + "/" + line + uripath - } + for _, line := range lines { + time.Sleep(time.Duration(delay) * time.Millisecond) + w.Wait() + go func(line string) { + var fullpath string + if uri[len(uri)-1:] == "/" { + fullpath = baseuri + line + uripath + "/" + } else { + fullpath = baseuri + "/" + line + uripath + } - statusCode, response, err := request(method, fullpath, headers, proxy) - if err != nil { - log.Println(err) - } + statusCode, response, err := request(method, fullpath, headers, proxy) + if err != nil { + log.Println(err) + } - results = append(results, Result{fullpath, statusCode, len(response)}) - w.Done() - }(line) + printResponse(Result{fullpath, statusCode, len(response)}) + w.Done() + }(line) + } + w.WaitAllDone() } - w.WaitAllDone() - printResponse(results) } // requestCapital makes HTTP requests by capitalizing each letter in the last part of the URI and prints the results. @@ -268,8 +261,6 @@ func requestCapital(uri string, headers []header, proxy *url.URL, method string) w := goccm.New(max_goroutines) - results := []Result{} - for _, z := range uripath { time.Sleep(time.Duration(delay) * time.Millisecond) w.Wait() @@ -294,12 +285,11 @@ func requestCapital(uri string, headers []header, proxy *url.URL, method string) log.Println(err) } - results = append(results, Result{fullpath, statusCode, len(response)}) + printResponse(Result{fullpath, statusCode, len(response)}) w.Done() }(z) } w.WaitAllDone() - printResponse(results) } // requester is the main function that runs all the tests. diff --git a/cmd/root.go b/cmd/root.go index 524f726..c850be1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -77,8 +77,8 @@ func init() { rootCmd.PersistentFlags().StringVarP(&uri, "uri", "u", "", "Target URL") rootCmd.PersistentFlags().StringVarP(&proxy, "proxy", "p", "", "Proxy URL. For example: http://127.0.0.1:8080") rootCmd.PersistentFlags().StringVarP(&useragent, "useragent", "a", "", "Set the User-Agent string (default 'dontgo403')") - rootCmd.PersistentFlags().IntVarP(&max_goroutines, "max_goroutines", "m", 50, "Set the max number of goroutines working at same time. Default: 50") - rootCmd.PersistentFlags().IntVarP(&delay, "delay", "d", 0, "Set a delay (in ms) between each request. Default: 0ms") + rootCmd.PersistentFlags().IntVarP(&max_goroutines, "max_goroutines", "m", 50, "Set the max number of goroutines working at same time") + rootCmd.PersistentFlags().IntVarP(&delay, "delay", "d", 0, "Set a delay (in ms) between each request (default 0ms)") rootCmd.PersistentFlags().StringSliceVarP(&req_headers, "header", "H", []string{""}, "Add a custom header to the requests (can be specified multiple times)") rootCmd.PersistentFlags().StringVarP(&bypassIp, "bypassIp", "b", "", "Try bypass tests with a specific IP address (or hostname). i.e.: 'X-Forwarded-For: 192.168.0.1' instead of 'X-Forwarded-For: 127.0.0.1'") rootCmd.PersistentFlags().StringVarP(&folder, "folder", "f", "", "Define payloads folder (if it's not in the same path as binary)") diff --git a/go.mod b/go.mod index 5a383ee..76174e6 100644 --- a/go.mod +++ b/go.mod @@ -25,8 +25,8 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.1 // indirect - golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect - golang.org/x/text v0.3.7 // indirect + golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect + golang.org/x/text v0.3.8 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 15d0e5d..a89f82d 100644 --- a/go.sum +++ b/go.sum @@ -324,8 +324,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -333,8 +333,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=