Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scraper functionality #633

Merged
merged 6 commits into from
Feb 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- New
- Added a new, dynamic keyword `FFUFHASH` that generates hash from job configuration and wordlist position to map blind payloads back to the initial request.
- New command line parameter for searching a hash: `-search FFUFHASH`
- Data scraper functionality
- Changed
- Multiline output prints out alphabetically sorted by keyword
- Default configuration directories now follow `XDG_CONFIG_HOME` variable (less spam in your home directory)
Expand Down
1 change: 1 addition & 0 deletions ffufrc.example
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
noninteractive = false
quiet = false
rate = 0
scrapers = "all"
stopon403 = false
stoponall = false
stoponerrors = false
Expand Down
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ module github.com/ffuf/ffuf
go 1.13

require (
github.com/PuerkitoBio/goquery v1.8.0
github.com/adrg/xdg v0.4.0
github.com/pelletier/go-toml v1.8.1
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pelletier/go-toml v1.9.5
golang.org/x/net v0.5.0 // indirect
)
41 changes: 38 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,17 +1,52 @@
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM=
github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
Expand Down
13 changes: 2 additions & 11 deletions help.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func Usage() {
Description: "",
Flags: make([]UsageFlag, 0),
Hidden: false,
ExpectedFlags: []string{"ac", "acc", "ack", "ach", "acs", "c", "config", "json", "maxtime", "maxtime-job", "noninteractive", "p", "rate", "search", "s", "sa", "se", "sf", "t", "v", "V"},
ExpectedFlags: []string{"ac", "acc", "ack", "ach", "acs", "c", "config", "json", "maxtime", "maxtime-job", "noninteractive", "p", "rate", "scraperfile", "scrapers", "search", "s", "sa", "se", "sf", "t", "v", "V"},
}
u_compat := UsageSection{
Name: "COMPATIBILITY OPTIONS",
Expand Down Expand Up @@ -105,7 +105,7 @@ func Usage() {
flag.VisitAll(func(f *flag.Flag) {
found := false
for i, section := range sections {
if strInSlice(f.Name, section.ExpectedFlags) {
if ffuf.StrInSlice(f.Name, section.ExpectedFlags) {
sections[i].Flags = append(sections[i].Flags, UsageFlag{
Name: f.Name,
Description: f.Usage,
Expand Down Expand Up @@ -149,12 +149,3 @@ func Usage() {

fmt.Printf(" More information and examples: https://github.com/ffuf/ffuf\n\n")
}

func strInSlice(val string, slice []string) bool {
for _, v := range slice {
if v == val {
return true
}
}
return false
}
28 changes: 23 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import (
"context"
"flag"
"fmt"
"io"
"log"
"os"
"strings"
"time"

"github.com/ffuf/ffuf/pkg/ffuf"
"github.com/ffuf/ffuf/pkg/filter"
"github.com/ffuf/ffuf/pkg/input"
"github.com/ffuf/ffuf/pkg/interactive"
"github.com/ffuf/ffuf/pkg/output"
"github.com/ffuf/ffuf/pkg/runner"
"io"
"log"
"os"
"strings"
"time"
"github.com/ffuf/ffuf/pkg/scraper"
)

type multiStringFlag []string
Expand Down Expand Up @@ -88,6 +90,8 @@ func ParseFlags(opts *ffuf.ConfigOptions) *ffuf.ConfigOptions {
flag.StringVar(&opts.General.AutoCalibrationKeyword, "ack", opts.General.AutoCalibrationKeyword, "Autocalibration keyword")
flag.StringVar(&opts.General.AutoCalibrationStrategy, "acs", opts.General.AutoCalibrationStrategy, "Autocalibration strategy: \"basic\" or \"advanced\"")
flag.StringVar(&opts.General.ConfigFile, "config", "", "Load configuration from a file")
flag.StringVar(&opts.General.ScraperFile, "scraperfile", "", "Custom scraper file path")
flag.StringVar(&opts.General.Scrapers, "scrapers", opts.General.Scrapers, "Active scraper groups")
flag.StringVar(&opts.Filter.Mode, "fmode", opts.Filter.Mode, "Filter set operator. Either of: and, or")
flag.StringVar(&opts.Filter.Lines, "fl", opts.Filter.Lines, "Filter by amount of lines in response. Comma separated list of line counts and ranges")
flag.StringVar(&opts.Filter.Regexp, "fr", opts.Filter.Regexp, "Filter regexp")
Expand Down Expand Up @@ -245,6 +249,7 @@ func main() {
}

func prepareJob(conf *ffuf.Config) (*ffuf.Job, error) {
var err error
job := ffuf.NewJob(conf)
var errs ffuf.Multierror
job.Input, errs = input.NewInputProvider(conf)
Expand All @@ -256,6 +261,19 @@ func prepareJob(conf *ffuf.Config) (*ffuf.Job, error) {
}
// We only have stdout outputprovider right now
job.Output = output.NewOutputProviderByName("stdout", conf)

// Initialize scraper
newscraper, scraper_err := scraper.FromDir(ffuf.SCRAPERDIR, conf.Scrapers)
if scraper_err.ErrorOrNil() != nil {
errs.Add(scraper_err.ErrorOrNil())
}
job.Scraper = newscraper
if conf.ScraperFile != "" {
err = job.Scraper.AppendFromFile(conf.ScraperFile)
if err != nil {
errs.Add(err)
}
}
return job, errs.ErrorOrNil()
}

Expand Down
4 changes: 4 additions & 0 deletions pkg/ffuf/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ type Config struct {
ReplayProxyURL string `json:"replayproxyurl"`
RequestFile string `json:"requestfile"`
RequestProto string `json:"requestproto"`
ScraperFile string `json:"scraperfile"`
Scrapers string `json:"scrapers"`
SNI string `json:"sni"`
StopOn403 bool `json:"stop_403"`
StopOnAll bool `json:"stop_all"`
Expand Down Expand Up @@ -107,6 +109,8 @@ func NewConfig(ctx context.Context, cancel context.CancelFunc) Config {
conf.RequestFile = ""
conf.RequestProto = "https"
conf.SNI = ""
conf.ScraperFile = ""
conf.Scrapers = "all"
conf.StopOn403 = false
conf.StopOnAll = false
conf.StopOnErrors = false
Expand Down
2 changes: 2 additions & 0 deletions pkg/ffuf/configmarshaller.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func (c *Config) ToOptions() ConfigOptions {
o.General.Noninteractive = c.Noninteractive
o.General.Quiet = c.Quiet
o.General.Rate = int(c.Rate)
o.General.ScraperFile = c.ScraperFile
o.General.Scrapers = c.Scrapers
o.General.StopOn403 = c.StopOn403
o.General.StopOnAll = c.StopOnAll
o.General.StopOnErrors = c.StopOnErrors
Expand Down
1 change: 1 addition & 0 deletions pkg/ffuf/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ var (
VERSION_APPENDIX = "-dev"
CONFIGDIR = filepath.Join(xdg.ConfigHome, "ffuf")
HISTORYDIR = filepath.Join(CONFIGDIR, "history")
SCRAPERDIR = filepath.Join(CONFIGDIR, "scraper")
)
7 changes: 0 additions & 7 deletions pkg/ffuf/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,4 @@ func configFromHistory(dirname string) (ConfigOptionsHistory, error) {
tmpOptions := ConfigOptionsHistory{}
err = json.Unmarshal(jsonOptions, &tmpOptions)
return tmpOptions, err
/*
// These are dummy values for this use case
ctx, cancel := context.WithCancel(context.Background())
conf, err := ConfigFromOptions(&tmpOptions.ConfigOptions, ctx, cancel)
job.Input, errs = input.NewInputProvider(conf)
return conf, tmpOptions.Time, err
*/
}
39 changes: 26 additions & 13 deletions pkg/ffuf/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,31 @@ type OutputProvider interface {
Cycle()
}

type Scraper interface {
Execute(resp *Response, matched bool) []ScraperResult
AppendFromFile(path string) error
}

type ScraperResult struct {
Name string `json:"name"`
Type string `json:"type"`
Action []string `json:"action"`
Results []string `json:"results"`
}

type Result struct {
Input map[string][]byte `json:"input"`
Position int `json:"position"`
StatusCode int64 `json:"status"`
ContentLength int64 `json:"length"`
ContentWords int64 `json:"words"`
ContentLines int64 `json:"lines"`
ContentType string `json:"content-type"`
RedirectLocation string `json:"redirectlocation"`
Url string `json:"url"`
Duration time.Duration `json:"duration"`
ResultFile string `json:"resultfile"`
Host string `json:"host"`
HTMLColor string `json:"-"`
Input map[string][]byte `json:"input"`
Position int `json:"position"`
StatusCode int64 `json:"status"`
ContentLength int64 `json:"length"`
ContentWords int64 `json:"words"`
ContentLines int64 `json:"lines"`
ContentType string `json:"content-type"`
RedirectLocation string `json:"redirectlocation"`
Url string `json:"url"`
Duration time.Duration `json:"duration"`
ScraperData map[string][]string `json:"scraper"`
ResultFile string `json:"resultfile"`
Host string `json:"host"`
HTMLColor string `json:"-"`
}
23 changes: 23 additions & 0 deletions pkg/ffuf/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type Job struct {
Input InputProvider
Runner RunnerProvider
ReplayRunner RunnerProvider
Scraper Scraper
Output OutputProvider
Jobhash string
Counter int
Expand Down Expand Up @@ -432,6 +433,14 @@ func (j *Job) runTask(input map[string][]byte, position int, retried bool) {
// Handle autocalibration, must be done after the actual request to ensure sane value in req.Host
_ = j.CalibrateIfNeeded(HostURLFromRequest(req), input)

// Handle scraper actions
if j.Scraper != nil {
for _, sres := range j.Scraper.Execute(&resp, j.isMatch(resp)) {
resp.ScraperData[sres.Name] = sres.Results
j.handleScraperResult(&resp, sres)
}
}

if j.isMatch(resp) {
// Re-send request through replay-proxy if needed
if j.ReplayRunner != nil {
Expand All @@ -452,13 +461,27 @@ func (j *Job) runTask(input map[string][]byte, position int, retried bool) {
if j.Config.Recursion && j.Config.RecursionStrategy == "greedy" {
j.handleGreedyRecursionJob(resp)
}
} else {
if len(resp.ScraperData) > 0 {
// print the result anyway, as scraper found something
j.Output.Result(resp)
}
}

if j.Config.Recursion && j.Config.RecursionStrategy == "default" && len(resp.GetRedirectLocation(false)) > 0 {
j.handleDefaultRecursionJob(resp)
}
}

func (j *Job) handleScraperResult(resp *Response, sres ScraperResult) {
for _, a := range sres.Action {
switch a {
case "output":
resp.ScraperData[sres.Name] = sres.Results
}
}
}

// handleGreedyRecursionJob adds a recursion job to the queue if the maximum depth has not been reached
func (j *Job) handleGreedyRecursionJob(resp Response) {
// Handle greedy recursion strategy. Match has been determined before calling handleRecursionJob
Expand Down
17 changes: 14 additions & 3 deletions pkg/ffuf/optionsparser.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ type GeneralOptions struct {
Noninteractive bool `json:"noninteractive"`
Quiet bool `json:"quiet"`
Rate int `json:"rate"`
ScraperFile string `json:"scraperfile"`
Scrapers string `json:"scrapers"`
Searchhash string `json:"-"`
ShowVersion bool `toml:"-" json:"-"`
StopOn403 bool `json:"stop_on_403"`
Expand Down Expand Up @@ -130,6 +132,8 @@ func NewConfigOptions() *ConfigOptions {
c.General.Quiet = false
c.General.Rate = 0
c.General.Searchhash = ""
c.General.ScraperFile = ""
c.General.Scrapers = "all"
c.General.ShowVersion = false
c.General.StopOn403 = false
c.General.StopOnAll = false
Expand Down Expand Up @@ -247,7 +251,13 @@ func ConfigFromOptions(parseOpts *ConfigOptions, ctx context.Context, cancel con
wl = strings.SplitN(v, ":", 2)
}
// Try to use absolute paths for wordlists
fullpath, err := filepath.Abs(wl[0])
fullpath := ""
if wl[0] != "-" {
fullpath, err = filepath.Abs(wl[0])
} else {
fullpath = wl[0]
}

if err == nil {
wl[0] = fullpath
}
Expand Down Expand Up @@ -456,6 +466,8 @@ func ConfigFromOptions(parseOpts *ConfigOptions, ctx context.Context, cancel con
conf.OutputSkipEmptyFile = parseOpts.Output.OutputSkipEmptyFile
conf.IgnoreBody = parseOpts.HTTP.IgnoreBody
conf.Quiet = parseOpts.General.Quiet
conf.ScraperFile = parseOpts.General.ScraperFile
conf.Scrapers = parseOpts.General.Scrapers
conf.StopOn403 = parseOpts.General.StopOn403
conf.StopOnAll = parseOpts.General.StopOnAll
conf.StopOnErrors = parseOpts.General.StopOnErrors
Expand Down Expand Up @@ -540,7 +552,6 @@ func ConfigFromOptions(parseOpts *ConfigOptions, ctx context.Context, cancel con
if parseOpts.General.Verbose && parseOpts.General.Json {
errs.Add(fmt.Errorf("Cannot have -json and -v"))
}

return &conf, errs.ErrorOrNil()
}

Expand Down Expand Up @@ -691,7 +702,7 @@ func ReadConfig(configFile string) (*ConfigOptions, error) {
func ReadDefaultConfig() (*ConfigOptions, error) {
// Try to create configuration directory, ignore the potential error
_ = CheckOrCreateConfigDir()
conffile := filepath.Join(CONFIGDIR, ".ffufrc")
conffile := filepath.Join(CONFIGDIR, "ffufrc")
if !FileExists(conffile) {
userhome, err := os.UserHomeDir()
if err == nil {
Expand Down
2 changes: 2 additions & 0 deletions pkg/ffuf/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Response struct {
Request *Request
Raw string
ResultFile string
ScraperData map[string][]string
Time time.Duration
}

Expand Down Expand Up @@ -86,5 +87,6 @@ func NewResponse(httpresp *http.Response, req *Request) Response {
resp.Cancelled = false
resp.Raw = ""
resp.ResultFile = ""
resp.ScraperData = make(map[string][]string)
return resp
}