Add word filter / matcher

This commit is contained in:
Joona Hoikkala 2018-11-12 19:06:49 +02:00
parent a1986d176a
commit fbafd82c62
No known key found for this signature in database
GPG Key ID: D5AA86BBF9B29A5C
6 changed files with 68 additions and 2 deletions

14
main.go
View File

@ -21,10 +21,12 @@ type cliOptions struct {
filterSize string filterSize string
filterReflect string filterReflect string
filterRegex string filterRegex string
filterWords string
matcherStatus string matcherStatus string
matcherSize string matcherSize string
matcherReflect string matcherReflect string
matcherRegex string matcherRegex string
matcherWords string
headers headerFlags headers headerFlags
} }
@ -50,12 +52,14 @@ func main() {
flag.BoolVar(&conf.TLSSkipVerify, "k", false, "Skip TLS identity verification (insecure)") flag.BoolVar(&conf.TLSSkipVerify, "k", false, "Skip TLS identity verification (insecure)")
flag.StringVar(&opts.filterStatus, "fc", "", "Filter HTTP status codes from response") flag.StringVar(&opts.filterStatus, "fc", "", "Filter HTTP status codes from response")
flag.StringVar(&opts.filterSize, "fs", "", "Filter HTTP response size") flag.StringVar(&opts.filterSize, "fs", "", "Filter HTTP response size")
flag.StringVar(&opts.filterWords, "fw", "", "Filter by amount of words in response")
flag.StringVar(&conf.Data, "d", "", "POST data.") flag.StringVar(&conf.Data, "d", "", "POST data.")
flag.BoolVar(&conf.Colors, "c", false, "Colorize output.") flag.BoolVar(&conf.Colors, "c", false, "Colorize output.")
//flag.StringVar(&opts.filterRegex, "fr", "", "Filter regex") //flag.StringVar(&opts.filterRegex, "fr", "", "Filter regex")
//flag.StringVar(&opts.filterReflect, "fref", "", "Filter reflected payload") //flag.StringVar(&opts.filterReflect, "fref", "", "Filter reflected payload")
flag.StringVar(&opts.matcherStatus, "mc", "200,204,301,302,307,401", "Match HTTP status codes from respose") flag.StringVar(&opts.matcherStatus, "mc", "200,204,301,302,307,401", "Match HTTP status codes from respose")
flag.StringVar(&opts.matcherSize, "ms", "", "Match HTTP response size") flag.StringVar(&opts.matcherSize, "ms", "", "Match HTTP response size")
flag.StringVar(&opts.matcherWords, "mw", "", "Match amount of words in response")
//flag.StringVar(&opts.matcherRegex, "mr", "", "Match regex") //flag.StringVar(&opts.matcherRegex, "mr", "", "Match regex")
flag.StringVar(&conf.Method, "X", "GET", "HTTP method to use.") flag.StringVar(&conf.Method, "X", "GET", "HTTP method to use.")
flag.BoolVar(&conf.Quiet, "s", false, "Do not print additional information (silent mode)") flag.BoolVar(&conf.Quiet, "s", false, "Do not print additional information (silent mode)")
@ -160,6 +164,11 @@ func prepareFilters(parseOpts *cliOptions, conf *ffuf.Config) error {
errlist = multierror.Append(errlist, err) errlist = multierror.Append(errlist, err)
} }
} }
if parseOpts.filterWords != "" {
if err := addFilter(conf, "word", parseOpts.filterWords); err != nil {
errlist = multierror.Append(errlist, err)
}
}
if parseOpts.matcherStatus != "" { if parseOpts.matcherStatus != "" {
if err := addMatcher(conf, "status", parseOpts.matcherStatus); err != nil { if err := addMatcher(conf, "status", parseOpts.matcherStatus); err != nil {
errlist = multierror.Append(errlist, err) errlist = multierror.Append(errlist, err)
@ -170,6 +179,11 @@ func prepareFilters(parseOpts *cliOptions, conf *ffuf.Config) error {
errlist = multierror.Append(errlist, err) errlist = multierror.Append(errlist, err)
} }
} }
if parseOpts.matcherWords != "" {
if err := addMatcher(conf, "word", parseOpts.matcherWords); err != nil {
errlist = multierror.Append(errlist, err)
}
}
return errlist.ErrorOrNil() return errlist.ErrorOrNil()
} }

View File

@ -10,6 +10,7 @@ type Response struct {
Headers map[string][]string Headers map[string][]string
Data []byte Data []byte
ContentLength int64 ContentLength int64
ContentWords int64
Cancelled bool Cancelled bool
Request *Request Request *Request
} }

View File

@ -1,6 +1,8 @@
package filter package filter
import ( import (
"fmt"
"github.com/ffuf/ffuf/pkg/ffuf" "github.com/ffuf/ffuf/pkg/ffuf"
) )
@ -11,5 +13,8 @@ func NewFilterByName(name string, value string) (ffuf.FilterProvider, error) {
if name == "size" { if name == "size" {
return NewSizeFilter(value) return NewSizeFilter(value)
} }
return nil, nil if name == "word" {
return NewWordFilter(value)
}
return nil, fmt.Errorf("Could not create filter with name %s", name)
} }

43
pkg/filter/words.go Normal file
View File

@ -0,0 +1,43 @@
package filter
import (
"fmt"
"strconv"
"strings"
"github.com/ffuf/ffuf/pkg/ffuf"
)
type WordFilter struct {
Value []int64
}
func NewWordFilter(value string) (ffuf.FilterProvider, error) {
var intvals []int64
for _, sv := range strings.Split(value, ",") {
intval, err := strconv.ParseInt(sv, 10, 0)
if err != nil {
return &WordFilter{}, fmt.Errorf("Word filter or matcher (-fw / -mw): invalid value: %s", value)
}
intvals = append(intvals, intval)
}
return &WordFilter{Value: intvals}, nil
}
func (f *WordFilter) Filter(response *ffuf.Response) (bool, error) {
wordsSize := len(strings.Split(string(response.Data), " "))
for _, iv := range f.Value {
if iv == int64(wordsSize) {
return true, nil
}
}
return false, nil
}
func (f *WordFilter) Repr() string {
var strval []string
for _, iv := range f.Value {
strval = append(strval, strconv.Itoa(int(iv)))
}
return fmt.Sprintf("Response words: %s", strings.Join(strval, ","))
}

View File

@ -98,7 +98,7 @@ func (s *Stdoutput) resultQuiet(resp ffuf.Response) {
} }
func (s *Stdoutput) resultNormal(resp ffuf.Response) { func (s *Stdoutput) resultNormal(resp ffuf.Response) {
res_str := fmt.Sprintf("%s%-23s [Status: %s, Size: %d]", TERMINAL_CLEAR_LINE, resp.Request.Input, s.colorizeStatus(resp.StatusCode), resp.ContentLength) res_str := fmt.Sprintf("%s%-23s [Status: %s, Size: %d, Words: %d]", TERMINAL_CLEAR_LINE, resp.Request.Input, s.colorizeStatus(resp.StatusCode), resp.ContentLength, resp.ContentWords)
fmt.Println(res_str) fmt.Println(res_str)
} }

View File

@ -94,5 +94,8 @@ func (r *SimpleRunner) Execute(req *ffuf.Request) (ffuf.Response, error) {
resp.Data = respbody resp.Data = respbody
} }
wordsSize := len(strings.Split(string(resp.Data), " "))
resp.ContentWords = int64(wordsSize)
return resp, nil return resp, nil
} }