ffuf/pkg/runner/simple.go

115 lines
3 KiB
Go
Raw Normal View History

2018-11-08 09:26:32 +00:00
package runner
import (
"bytes"
"crypto/tls"
"fmt"
2018-11-08 09:26:32 +00:00
"io/ioutil"
"net/http"
"strconv"
"strings"
"time"
"unicode/utf8"
"github.com/ffuf/ffuf/pkg/ffuf"
)
//Download results < 5MB
const MAX_DOWNLOAD_SIZE = 5242880
type SimpleRunner struct {
config *ffuf.Config
client *http.Client
}
func NewSimpleRunner(conf *ffuf.Config) ffuf.RunnerProvider {
var simplerunner SimpleRunner
simplerunner.config = conf
simplerunner.client = &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse },
Timeout: time.Duration(time.Duration(conf.Timeout) * time.Second),
2018-11-08 09:26:32 +00:00
Transport: &http.Transport{
2019-01-21 20:43:04 +00:00
Proxy: conf.ProxyURL,
2018-11-14 20:38:13 +00:00
MaxIdleConns: 1000,
MaxIdleConnsPerHost: 500,
MaxConnsPerHost: 500,
2018-11-08 09:26:32 +00:00
TLSClientConfig: &tls.Config{
InsecureSkipVerify: !conf.TLSVerify,
2018-11-08 09:26:32 +00:00
},
}}
2019-04-03 09:54:32 +00:00
if conf.FollowRedirects {
simplerunner.client.CheckRedirect = nil
}
2018-11-08 09:26:32 +00:00
return &simplerunner
}
func (r *SimpleRunner) Prepare(input []byte) (ffuf.Request, error) {
req := ffuf.NewRequest(r.config)
// should we fuzz the http method
if r.config.Method == "FUZZ" {
req.Method = string(input)
}
2018-11-08 09:26:32 +00:00
for h, v := range r.config.StaticHeaders {
req.Headers[h] = v
}
for h, v := range r.config.FuzzHeaders {
req.Headers[strings.Replace(h, "FUZZ", string(input), -1)] = strings.Replace(v, "FUZZ", string(input), -1)
}
req.Input = input
req.Url = strings.Replace(r.config.Url, "FUZZ", string(input), -1)
2018-11-08 09:49:06 +00:00
req.Data = []byte(strings.Replace(r.config.Data, "FUZZ", string(input), -1))
2018-11-08 09:26:32 +00:00
return req, nil
}
func (r *SimpleRunner) Execute(req *ffuf.Request) (ffuf.Response, error) {
var httpreq *http.Request
var err error
data := bytes.NewReader(req.Data)
httpreq, err = http.NewRequest(req.Method, req.Url, data)
if err != nil {
return ffuf.Response{}, err
}
// Add user agent string if not defined
if _, ok := req.Headers["User-Agent"]; !ok {
req.Headers["User-Agent"] = fmt.Sprintf("%s v%s", "Fuzz Faster U Fool", ffuf.VERSION)
2018-11-08 09:26:32 +00:00
}
2018-11-09 13:21:23 +00:00
// Handle Go http.Request special cases
if _, ok := req.Headers["Host"]; ok {
httpreq.Host = req.Headers["Host"]
}
2018-11-08 09:26:32 +00:00
httpreq = httpreq.WithContext(r.config.Context)
for k, v := range req.Headers {
httpreq.Header.Set(k, v)
}
httpresp, err := r.client.Do(httpreq)
if err != nil {
return ffuf.Response{}, err
}
resp := ffuf.NewResponse(httpresp, req)
defer httpresp.Body.Close()
// Check if we should download the resource or not
size, err := strconv.Atoi(httpresp.Header.Get("Content-Length"))
if err == nil {
resp.ContentLength = int64(size)
if size > MAX_DOWNLOAD_SIZE {
resp.Cancelled = true
return resp, nil
}
}
if respbody, err := ioutil.ReadAll(httpresp.Body); err == nil {
resp.ContentLength = int64(utf8.RuneCountInString(string(respbody)))
resp.Data = respbody
}
2018-11-12 17:06:49 +00:00
wordsSize := len(strings.Split(string(resp.Data), " "))
linesSize := len(strings.Split(string(resp.Data), "\n"))
2018-11-12 17:06:49 +00:00
resp.ContentWords = int64(wordsSize)
resp.ContentLines = int64(linesSize)
2018-11-12 17:06:49 +00:00
2018-11-08 09:26:32 +00:00
return resp, nil
}