这是indexloc提供的服务,不要输入任何密码
Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func main() {
flag.StringVar(&opts.proxyURL, "x", "", "HTTP Proxy URL")
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.StopOn403, "sf", false, "Stop when > 90% of responses return 403 Forbidden")
flag.IntVar(&conf.Threads, "t", 40, "Number of concurrent threads.")
flag.BoolVar(&opts.showVersion, "V", false, "Show version information.")
flag.Parse()
Expand Down
2 changes: 2 additions & 0 deletions pkg/ffuf/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Config struct {
Quiet bool
Colors bool
Wordlist string
StopOn403 bool
Delay optRange
Filters []FilterProvider
Matchers []FilterProvider
Expand All @@ -43,6 +44,7 @@ func NewConfig(ctx context.Context) Config {
conf.TLSSkipVerify = false
conf.Data = ""
conf.Quiet = false
conf.StopOn403 = false
conf.ProxyURL = http.ProxyFromEnvironment
conf.Filters = make([]FilterProvider, 0)
conf.Delay = optRange{0, 0, false, false}
Expand Down
2 changes: 2 additions & 0 deletions pkg/ffuf/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type InputProvider interface {
type OutputProvider interface {
Banner() error
Finalize() error
Progress(status string)
Error(errstring string)
Warning(warnstring string)
Result(resp Response) bool
}
35 changes: 29 additions & 6 deletions pkg/ffuf/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ type Job struct {
Counter int
Total int
Running bool
Count403 int
Error string
startTime time.Time
}

Expand All @@ -42,6 +44,12 @@ func (j *Job) Start() {
//Limiter blocks after reaching the buffer, ensuring limited concurrency
limiter := make(chan bool, j.Config.Threads)
for j.Input.Next() {
// Check if we should stop the process
j.CheckStop()
if !j.Running {
defer j.Output.Warning(j.Error)
break
}
limiter <- true
nextInput := j.Input.Value()
wg.Add(1)
Expand Down Expand Up @@ -73,6 +81,9 @@ func (j *Job) runProgress(wg *sync.WaitGroup) {
j.startTime = time.Now()
totalProgress := j.Input.Total()
for j.Counter <= totalProgress {
if !j.Running {
break
}
j.updateProgress()
if j.Counter == totalProgress {
return
Expand All @@ -82,11 +93,6 @@ func (j *Job) runProgress(wg *sync.WaitGroup) {
}

func (j *Job) updateProgress() {
//TODO: refactor to use a defined progress struct for future output modules
if j.Config.Quiet {
// Do not print progress status in silent mode
return
}
runningSecs := int((time.Now().Sub(j.startTime)) / time.Second)
var reqRate int
if runningSecs > 0 {
Expand All @@ -101,7 +107,7 @@ func (j *Job) updateProgress() {
dur -= mins * time.Minute
secs := dur / time.Second
progString := fmt.Sprintf(":: Progress: [%d/%d] :: %d req/sec :: Duration: [%d:%02d:%02d] ::", j.Counter, j.Total, int(reqRate), hours, mins, secs)
j.Output.Error(progString)
j.Output.Progress(progString)
}

func (j *Job) runTask(input []byte) {
Expand All @@ -115,13 +121,30 @@ func (j *Job) runTask(input []byte) {
j.Output.Error(fmt.Sprintf("Error in runner: %s\n", err))
return
}
if j.Config.StopOn403 {
// Incremnt Forbidden counter if we encountered one
if resp.StatusCode == 403 {
j.Count403 += 1
}
}
if j.Output.Result(resp) {
// Refresh the progress indicator as we printed something out
j.updateProgress()
}
return
}

func (j *Job) CheckStop() {
if j.Counter > 50 {
// We have enough samples
if float64(j.Count403)/float64(j.Counter) > 0.95 {
// Over 95% of requests are 403
j.Error = "Getting unusual amount of 403 responses, exiting."
j.Stop()
}
}
}

//Stop the execution of the Job
func (j *Job) Stop() {
j.Running = false
Expand Down
27 changes: 26 additions & 1 deletion pkg/output/stdout.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,36 @@ func (s *Stdoutput) Banner() error {
return nil
}

func (s *Stdoutput) Progress(status string) {
if s.config.Quiet {
// No progress for quiet mode
return
} else {
fmt.Fprintf(os.Stderr, "%s%s", TERMINAL_CLEAR_LINE, status)
}
}

func (s *Stdoutput) Error(errstring string) {
if s.config.Quiet {
fmt.Fprintf(os.Stderr, "%s", errstring)
} else {
fmt.Fprintf(os.Stderr, "%s%s", TERMINAL_CLEAR_LINE, errstring)
if !s.config.Colors {
fmt.Fprintf(os.Stderr, "%s[ERR] %s\n", TERMINAL_CLEAR_LINE, errstring)
} else {
fmt.Fprintf(os.Stderr, "%s[%sERR%s] %s\n", TERMINAL_CLEAR_LINE, ANSI_RED, ANSI_CLEAR, errstring)
}
}
}

func (s *Stdoutput) Warning(warnstring string) {
if s.config.Quiet {
fmt.Fprintf(os.Stderr, "%s", warnstring)
} else {
if !s.config.Colors {
fmt.Fprintf(os.Stderr, "%s[WARN] %s", TERMINAL_CLEAR_LINE, warnstring)
} else {
fmt.Fprintf(os.Stderr, "%s[%sWARN%s] %s\n", TERMINAL_CLEAR_LINE, ANSI_RED, ANSI_CLEAR, warnstring)
}
}
}

Expand Down