From 53edf8638bab79598bc1668a81a8ae9e44f8d8c0 Mon Sep 17 00:00:00 2001 From: Lou Onezime Date: Sun, 8 Sep 2024 19:36:48 +0200 Subject: [PATCH 1/3] feat(match): base of feature possibility of mult headers + body --- README.md | 12 ++++++++++++ src/matching/headers.go | 2 +- src/matching/matcher.go | 5 +++-- src/models/models.go | 16 +++++++++++++--- src/query/callWorker.go | 7 ++++++- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 80b8046..3ea286e 100644 --- a/README.md +++ b/README.md @@ -54,10 +54,22 @@ For example, `./bruteforce -status-codes="200,201,202,401,404"`. For example, `./bruteforce -header="Content-Type: application/json"`. +To match multiple headers, use commas to separate each querie. Specify `ALL` if you wish to have all matches be true, if not don't add the `ALL`. As so: + +- should match all of the headers: + +`./bruteforce -header="ALL,Content-Type: application/json,Content-Type: text/css"` + +- match on any of the headers: + +`./bruteforce -header="Content-Type: application/json,Content-Type: text/css"` + `-body` : match based on a body. For example, `./bruteforce -body="Hello World"`. +Same applies the body for multiple queries of strings in the body as the header. + ## Get involved You're invited to join this project ! Check out the [contributing guide](./CONTRIBUTING.md). diff --git a/src/matching/headers.go b/src/matching/headers.go index 9bae1bb..b278366 100644 --- a/src/matching/headers.go +++ b/src/matching/headers.go @@ -9,7 +9,7 @@ import ( ) func matchHeaders(resp *http.Response, criteria models.MatchCriteria) error { - for key, value := range criteria.Headers { + for key, value := range criteria.Headers.Headers { if resp.Header.Get(key) != value { return fmt.Errorf("header mismatch: %s=%s\nheaders: %s", key, value, resp.Header) } diff --git a/src/matching/matcher.go b/src/matching/matcher.go index 687dc60..541b994 100644 --- a/src/matching/matcher.go +++ b/src/matching/matcher.go @@ -4,6 +4,7 @@ import ( "bruteforce/src/models" "log" "net/http" + "strings" ) func MatchResponse(response *http.Response, body []byte, criteria models.MatchCriteria) error { @@ -29,8 +30,8 @@ func MatchParser(statusPtr string, headerPtr string, bodyPtr string) models.Matc matchHeaders := parseHeaders(headerPtr) criteria := models.MatchCriteria{ StatusCodes: matchCodes, - Headers: matchHeaders, - BodyContains: bodyPtr, + Headers: models.HeaderMatch {Headers: matchHeaders, MatchAllHeader: false}, + BodyContains: models.BodyMatch {BodyContains: bodyPtr, MatchAllBody: false}, } return criteria diff --git a/src/models/models.go b/src/models/models.go index 1e8ea73..d8b217a 100644 --- a/src/models/models.go +++ b/src/models/models.go @@ -4,10 +4,20 @@ type boolflags struct { Verbose bool } +type HeaderMatch struct { + Headers map[string]string + MatchAllHeader bool +} + +type BodyMatch struct { + BodyContains string + MatchAllBody bool +} + type MatchCriteria struct { - StatusCodes []int - Headers map[string]string - BodyContains string + StatusCodes []int + Headers HeaderMatch + BodyContains BodyMatch } type ForcingParams struct { diff --git a/src/query/callWorker.go b/src/query/callWorker.go index 56332b9..ae8d2a6 100644 --- a/src/query/callWorker.go +++ b/src/query/callWorker.go @@ -8,8 +8,13 @@ import ( func executeQueryFromFile(wg *sync.WaitGroup, params *models.ForcingParams, currentPath chan string) { defer wg.Done() + + if (params.Url[len(params.Url) - 1] != '/'){ + params.Url = params.Url + "/" + } + for taskData := range currentPath { - QueryExecute(params, taskData, "GET") + QueryExecute(params, taskData, "POST") } } From a854a5684b0aef1e254372e4c658524d2104e564 Mon Sep 17 00:00:00 2001 From: Lou Onezime Date: Wed, 18 Sep 2024 18:54:36 +0200 Subject: [PATCH 2/3] feat(matcher): make parsing of flags more robust for multiple and accurate matching --- src/matching/body.go | 41 ++++++++++++++++++++++++++++++++++++++--- src/matching/headers.go | 25 ++++++++++++++++++++----- src/matching/matcher.go | 9 +++++---- src/models/models.go | 14 +++++++------- src/query/callWorker.go | 2 +- 5 files changed, 71 insertions(+), 20 deletions(-) diff --git a/src/matching/body.go b/src/matching/body.go index 9ccf9f5..e25c3c6 100644 --- a/src/matching/body.go +++ b/src/matching/body.go @@ -2,13 +2,48 @@ package matcher import ( "bruteforce/src/models" - "errors" + "fmt" + "log" "strings" ) func matchContents(body []byte, criteria models.MatchCriteria) error { - if criteria.BodyContains != "" && !strings.Contains(string(body), criteria.BodyContains) { - return errors.New("body content mismatch") + bodyStr := string(body) + + if len(criteria.Body.BodyContains) > 0 { + for _, content := range criteria.Body.BodyContains { + if !strings.Contains(bodyStr, content) { + return fmt.Errorf("body content mismatch: missing %s", content) + } + } } return nil } + +func parseBody(body string) models.BodyMatch { + if body == "" { + return models.BodyMatch{} + } + + parts := strings.Split(body, ",") + firstPart := strings.TrimSpace(parts[0]) + mode := true + + if firstPart == "all" { + parts = parts[1:] + log.Println("[INFO] Matching criteria for body is set to check if.") + } else if firstPart == "one" { + mode = !mode + parts = parts[1:] + log.Println("[INFO] Matching criteria for body is set to check if one true.") + } + + var parsedBody []string + for _, part := range parts { + part = strings.TrimSpace(part) + if part != "" { + parsedBody = append(parsedBody, part) + } + } + return models.BodyMatch{BodyContains: parsedBody, MatchAllBody: mode} +} diff --git a/src/matching/headers.go b/src/matching/headers.go index b278366..2fbfa3a 100644 --- a/src/matching/headers.go +++ b/src/matching/headers.go @@ -9,7 +9,7 @@ import ( ) func matchHeaders(resp *http.Response, criteria models.MatchCriteria) error { - for key, value := range criteria.Headers.Headers { + for key, value := range criteria.Header.Headers { if resp.Header.Get(key) != value { return fmt.Errorf("header mismatch: %s=%s\nheaders: %s", key, value, resp.Header) } @@ -17,21 +17,36 @@ func matchHeaders(resp *http.Response, criteria models.MatchCriteria) error { return nil } -func parseHeaders(headersList string) map[string]string { +func parseHeaders(headersList string) models.HeaderMatch { if headersList == "" { - return nil + return models.HeaderMatch{} } headers := make(map[string]string) headerPairs := strings.Split(headersList, ",") + mode := true + firstPair := strings.TrimSpace(headerPairs[0]) + + if strings.HasPrefix(firstPair, "all") { + headerPairs = headerPairs[1:] + log.Println("[INFO] Matching criteria for header is set to check if.") + } else if strings.HasPrefix(firstPair, "one") { + mode = !mode + headerPairs = headerPairs[1:] + log.Println("[INFO] Matching criteria for header is set to check if one true.") + } for _, pair := range headerPairs { parts := strings.SplitN(pair, ":", 2) if len(parts) == 2 { - headers[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) + key := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) + + log.Printf("[INFO] Parsed header: %s=%s", key, value) + headers[key] = value } else { log.Printf("[WARN] Invalid header format: %s", pair) } } - return headers + return models.HeaderMatch{Headers: headers, MatchAllHeader: mode} } diff --git a/src/matching/matcher.go b/src/matching/matcher.go index 541b994..817336a 100644 --- a/src/matching/matcher.go +++ b/src/matching/matcher.go @@ -4,7 +4,6 @@ import ( "bruteforce/src/models" "log" "net/http" - "strings" ) func MatchResponse(response *http.Response, body []byte, criteria models.MatchCriteria) error { @@ -28,10 +27,12 @@ func MatchParser(statusPtr string, headerPtr string, bodyPtr string) models.Matc } matchHeaders := parseHeaders(headerPtr) + matchBody := parseBody(bodyPtr) + criteria := models.MatchCriteria{ - StatusCodes: matchCodes, - Headers: models.HeaderMatch {Headers: matchHeaders, MatchAllHeader: false}, - BodyContains: models.BodyMatch {BodyContains: bodyPtr, MatchAllBody: false}, + StatusCodes: matchCodes, + Header: matchHeaders, + Body: matchBody, } return criteria diff --git a/src/models/models.go b/src/models/models.go index d8b217a..63b8078 100644 --- a/src/models/models.go +++ b/src/models/models.go @@ -5,19 +5,19 @@ type boolflags struct { } type HeaderMatch struct { - Headers map[string]string - MatchAllHeader bool + Headers map[string]string + MatchAllHeader bool } type BodyMatch struct { - BodyContains string - MatchAllBody bool + BodyContains []string + MatchAllBody bool } type MatchCriteria struct { - StatusCodes []int - Headers HeaderMatch - BodyContains BodyMatch + StatusCodes []int + Header HeaderMatch + Body BodyMatch } type ForcingParams struct { diff --git a/src/query/callWorker.go b/src/query/callWorker.go index ae8d2a6..3e6e938 100644 --- a/src/query/callWorker.go +++ b/src/query/callWorker.go @@ -9,7 +9,7 @@ import ( func executeQueryFromFile(wg *sync.WaitGroup, params *models.ForcingParams, currentPath chan string) { defer wg.Done() - if (params.Url[len(params.Url) - 1] != '/'){ + if params.Url[len(params.Url)-1] != '/' { params.Url = params.Url + "/" } From abcab133c6e98a9dbeabfdbcfaab68b1056affe9 Mon Sep 17 00:00:00 2001 From: Lou Onezime Date: Wed, 18 Sep 2024 19:41:34 +0200 Subject: [PATCH 3/3] fix(doc): readme is adapted to code --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ea286e..6a847e8 100644 --- a/README.md +++ b/README.md @@ -58,11 +58,11 @@ To match multiple headers, use commas to separate each querie. Specify `ALL` if - should match all of the headers: -`./bruteforce -header="ALL,Content-Type: application/json,Content-Type: text/css"` +`./bruteforce -header="all,Content-Type: application/json,Content-Type: text/css"` - match on any of the headers: -`./bruteforce -header="Content-Type: application/json,Content-Type: text/css"` +`./bruteforce -header="one,Content-Type: application/json,Content-Type: text/css"` `-body` : match based on a body.