diff --git a/README.md b/README.md index 2ec94a5..80b8046 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,14 @@ For example, `./bruteforce -status-codes="200,201,202,401,404"`. *By default* : 200, 401, 403, 404, 429, 500 +`-header` : match based on a header. + +For example, `./bruteforce -header="Content-Type: application/json"`. + +`-body` : match based on a body. + +For example, `./bruteforce -body="Hello World"`. + ## Get involved You're invited to join this project ! Check out the [contributing guide](./CONTRIBUTING.md). diff --git a/src/main.go b/src/main.go index efa588f..8dd2027 100644 --- a/src/main.go +++ b/src/main.go @@ -9,6 +9,8 @@ import ( func main() { usagePtr := flag.Bool("help", false, "a bool") statusPtr := flag.String("status-codes", "200,401,403,404,429,500", "Comma-separated list of status codes to match") + headerPtr := flag.String("header", "", "Header to match") + bodyPtr := flag.String("body", "", "String to match in response body") flag.Parse() if *usagePtr { @@ -18,5 +20,5 @@ func main() { fmt.Println("\t\t\t[By default: 200,401,403,404,429,500]") return; } - matcher.MatchParser("http://example.com", *statusPtr) + matcher.MatchParser("http://example.com", *statusPtr, *headerPtr, *bodyPtr) } diff --git a/src/matching/body.go b/src/matching/body.go new file mode 100644 index 0000000..54a1dce --- /dev/null +++ b/src/matching/body.go @@ -0,0 +1,10 @@ +package matcher + +import "strings" + +func matchContents(body []byte, criteria MatchCriteria) (bool, string) { + if criteria.BodyContains != "" && !strings.Contains(string(body), criteria.BodyContains) { + return false, "body content mismatch" + } + return true, "body content matches" +} diff --git a/src/matching/headers.go b/src/matching/headers.go new file mode 100644 index 0000000..1514f37 --- /dev/null +++ b/src/matching/headers.go @@ -0,0 +1,36 @@ +package matcher + +import ( + "fmt" + "strings" + "net/http" + "log" +) + +func matchHeaders(resp *http.Response, criteria MatchCriteria) (bool, string) { + for key, value := range criteria.Headers { + if resp.Header.Get(key) != value { + return false, fmt.Sprintf("header mismatch: %s=%s", key, value) + } + } + return true, "headers match" +} + +func parseHeaders(headersList string) map[string]string { + if headersList == "" { + return nil + } + + headers := make(map[string]string) + headerPairs := strings.Split(headersList, ",") + + for _, pair := range headerPairs { + parts := strings.SplitN(pair, ":", 2) + if len(parts) == 2 { + headers[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) + } else { + log.Printf("[WARN] Invalid header format: %s", pair) + } + } + return headers +} diff --git a/src/matching/matcher.go b/src/matching/matcher.go index ce6b834..46ef078 100644 --- a/src/matching/matcher.go +++ b/src/matching/matcher.go @@ -2,15 +2,50 @@ package matcher import ( "log" + "io/ioutil" + "fmt" + "net/http" ) -func MatchParser(url string, statuses string) { +type MatchCriteria struct { + StatusCodes []int + Headers map[string]string + BodyContains string +} + +func matchResponse(url string, criteria MatchCriteria) (bool, string) { + resp, err := http.Get(url) + if err != nil { + return false, err.Error() + } + defer resp.Body.Close() + + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return false, err.Error() + } + + matchStatusCode(resp, criteria.StatusCodes) + matchHeaders(resp, criteria) + matchContents(body, criteria) + + return false, fmt.Sprintf("status code is %d", resp.StatusCode) +} + +func MatchParser(url string, statuses string, headers string, bodyContains string) { matchCodes, err := parseStatusCodes(statuses) if err != nil { log.Fatal("Error parsing status codes:", err) } - matched, msg := matchStatusCode(url, matchCodes) + matchHeaders := parseHeaders(headers) + criteria := MatchCriteria{ + StatusCodes: matchCodes, + Headers: matchHeaders, + BodyContains: bodyContains, + } + + matched, msg := matchResponse(url, criteria) if matched { log.Println("Matched:", msg) } else { diff --git a/src/matching/status_codes.go b/src/matching/status_codes.go index 68354c5..732b2d9 100644 --- a/src/matching/status_codes.go +++ b/src/matching/status_codes.go @@ -7,14 +7,8 @@ import ( "log" ) - -func matchStatusCode(url string, matchCodes []int) (bool, string) { +func matchStatusCode(resp *http.Response, matchCodes []int) (bool, string) { isAll := false - resp, err := http.Get(url) - if err != nil { - return false, err.Error() - } - defer resp.Body.Close() if matchCodes[0] == 0 { isAll = !isAll; @@ -31,7 +25,6 @@ func matchStatusCode(url string, matchCodes []int) (bool, string) { func parseStatusCodes(statusCodeList string) ([]int, error) { codeStrs := strings.Split(statusCodeList, ",") - if statusCodeList == "all" { log.Println("Matching all status codes") return []int{0}, nil