code refactor

This commit is contained in:
Mzack9999 2020-07-18 21:42:23 +02:00
parent 6d7bb9a2c3
commit 57a496203f
8 changed files with 291 additions and 288 deletions

View File

@ -112,7 +112,7 @@ func (r *Runner) RunEnumeration() {
var results bool var results bool
template := t.(*templates.Template) template := t.(*templates.Template)
// process http requests // process http requests
for _, request := range template.RequestsHTTP { for _, request := range template.BulkRequestsHTTP {
results = r.processTemplateRequest(template, request) results = r.processTemplateRequest(template, request)
} }
// process dns requests // process dns requests
@ -176,7 +176,7 @@ func (r *Runner) RunEnumeration() {
results = dnsResults results = dnsResults
} }
} }
for _, request := range template.RequestsHTTP { for _, request := range template.BulkRequestsHTTP {
httpResults := r.processTemplateRequest(template, request) httpResults := r.processTemplateRequest(template, request)
if httpResults { if httpResults {
results = httpResults results = httpResults
@ -248,11 +248,11 @@ func (r *Runner) processTemplateWithList(template *templates.Template, request i
Writer: writer, Writer: writer,
JSON: r.options.JSON, JSON: r.options.JSON,
}) })
case *requests.HTTPRequest: case *requests.BulkHTTPRequest:
httpExecuter, err = executer.NewHTTPExecuter(&executer.HTTPOptions{ httpExecuter, err = executer.NewHTTPExecuter(&executer.HTTPOptions{
Debug: r.options.Debug, Debug: r.options.Debug,
Template: template, Template: template,
HTTPRequest: value, BulkHttpRequest: value,
Writer: writer, Writer: writer,
Timeout: r.options.Timeout, Timeout: r.options.Timeout,
Retries: r.options.Retries, Retries: r.options.Retries,
@ -302,11 +302,11 @@ func (r *Runner) processTemplateWithList(template *templates.Template, request i
// See if we got any results from the executers // See if we got any results from the executers
var results bool var results bool
if httpExecuter != nil { if httpExecuter != nil {
results = httpExecuter.GotResults() results = httpExecuter.Results
} }
if dnsExecuter != nil { if dnsExecuter != nil {
if !results { if !results {
results = dnsExecuter.GotResults() results = dnsExecuter.Results
} }
} }
return results return results
@ -376,7 +376,7 @@ func (r *Runner) ProcessWorkflow(workflow *workflows.Workflow, URL string) error
return err return err
} }
template := &workflows.Template{} template := &workflows.Template{}
if len(t.RequestsHTTP) > 0 { if len(t.BulkRequestsHTTP) > 0 {
template.HTTPOptions = &executer.HTTPOptions{ template.HTTPOptions = &executer.HTTPOptions{
Debug: r.options.Debug, Debug: r.options.Debug,
Writer: writer, Writer: writer,
@ -427,7 +427,7 @@ func (r *Runner) ProcessWorkflow(workflow *workflows.Workflow, URL string) error
return err return err
} }
template := &workflows.Template{} template := &workflows.Template{}
if len(t.RequestsHTTP) > 0 { if len(t.BulkRequestsHTTP) > 0 {
template.HTTPOptions = &executer.HTTPOptions{ template.HTTPOptions = &executer.HTTPOptions{
Debug: r.options.Debug, Debug: r.options.Debug,
Writer: writer, Writer: writer,

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"os" "os"
"sync" "sync"
"sync/atomic"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/projectdiscovery/gologger" "github.com/projectdiscovery/gologger"
@ -20,7 +19,7 @@ import (
type DNSExecuter struct { type DNSExecuter struct {
debug bool debug bool
jsonOutput bool jsonOutput bool
results uint32 Results bool
dnsClient *retryabledns.Client dnsClient *retryabledns.Client
template *templates.Template template *templates.Template
dnsRequest *requests.DNSRequest dnsRequest *requests.DNSRequest
@ -53,7 +52,6 @@ func NewDNSExecuter(options *DNSOptions) *DNSExecuter {
executer := &DNSExecuter{ executer := &DNSExecuter{
debug: options.Debug, debug: options.Debug,
jsonOutput: options.JSON, jsonOutput: options.JSON,
results: 0,
dnsClient: dnsClient, dnsClient: dnsClient,
template: options.Template, template: options.Template,
dnsRequest: options.DNSRequest, dnsRequest: options.DNSRequest,
@ -63,14 +61,6 @@ func NewDNSExecuter(options *DNSOptions) *DNSExecuter {
return executer return executer
} }
// GotResults returns true if there were any results for the executer
func (e *DNSExecuter) GotResults() bool {
if atomic.LoadUint32(&e.results) == 0 {
return false
}
return true
}
// ExecuteDNS executes the DNS request on a URL // ExecuteDNS executes the DNS request on a URL
func (e *DNSExecuter) ExecuteDNS(URL string) (result Result) { func (e *DNSExecuter) ExecuteDNS(URL string) (result Result) {
// Parse the URL and return domain if URL. // Parse the URL and return domain if URL.
@ -120,7 +110,7 @@ func (e *DNSExecuter) ExecuteDNS(URL string) (result Result) {
// write the first output then move to next matcher. // write the first output then move to next matcher.
if matcherCondition == matchers.ORCondition && len(e.dnsRequest.Extractors) == 0 { if matcherCondition == matchers.ORCondition && len(e.dnsRequest.Extractors) == 0 {
e.writeOutputDNS(domain, matcher, nil) e.writeOutputDNS(domain, matcher, nil)
atomic.CompareAndSwapUint32(&e.results, 0, 1) e.Results = true
} }
} }
} }
@ -138,7 +128,7 @@ func (e *DNSExecuter) ExecuteDNS(URL string) (result Result) {
// AND or if we have extractors for the mechanism too. // AND or if we have extractors for the mechanism too.
if len(e.dnsRequest.Extractors) > 0 || matcherCondition == matchers.ANDCondition { if len(e.dnsRequest.Extractors) > 0 || matcherCondition == matchers.ANDCondition {
e.writeOutputDNS(domain, nil, extractorResults) e.writeOutputDNS(domain, nil, extractorResults)
atomic.CompareAndSwapUint32(&e.results, 0, 1) e.Results = true
} }
return return
@ -147,6 +137,6 @@ func (e *DNSExecuter) ExecuteDNS(URL string) (result Result) {
// Close closes the dns executer for a template. // Close closes the dns executer for a template.
func (e *DNSExecuter) Close() { func (e *DNSExecuter) Close() {
e.outputMutex.Lock() e.outputMutex.Lock()
defer e.outputMutex.Unlock()
e.writer.Flush() e.writer.Flush()
e.outputMutex.Unlock()
} }

View File

@ -13,7 +13,6 @@ import (
"os" "os"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -29,11 +28,11 @@ import (
// for a template. // for a template.
type HTTPExecuter struct { type HTTPExecuter struct {
debug bool debug bool
results uint32 Results bool
jsonOutput bool jsonOutput bool
httpClient *retryablehttp.Client httpClient *retryablehttp.Client
template *templates.Template template *templates.Template
httpRequest *requests.HTTPRequest bulkHttpRequest *requests.BulkHTTPRequest
writer *bufio.Writer writer *bufio.Writer
outputMutex *sync.Mutex outputMutex *sync.Mutex
customHeaders requests.CustomHeaders customHeaders requests.CustomHeaders
@ -43,7 +42,7 @@ type HTTPExecuter struct {
// HTTPOptions contains configuration options for the HTTP executer. // HTTPOptions contains configuration options for the HTTP executer.
type HTTPOptions struct { type HTTPOptions struct {
Template *templates.Template Template *templates.Template
HTTPRequest *requests.HTTPRequest BulkHttpRequest *requests.BulkHTTPRequest
Writer *bufio.Writer Writer *bufio.Writer
Timeout int Timeout int
Retries int Retries int
@ -85,10 +84,9 @@ func NewHTTPExecuter(options *HTTPOptions) (*HTTPExecuter, error) {
executer := &HTTPExecuter{ executer := &HTTPExecuter{
debug: options.Debug, debug: options.Debug,
jsonOutput: options.JSON, jsonOutput: options.JSON,
results: 0,
httpClient: client, httpClient: client,
template: options.Template, template: options.Template,
httpRequest: options.HTTPRequest, bulkHttpRequest: options.BulkHttpRequest,
outputMutex: &sync.Mutex{}, outputMutex: &sync.Mutex{},
writer: options.Writer, writer: options.Writer,
customHeaders: options.CustomHeaders, customHeaders: options.CustomHeaders,
@ -97,43 +95,40 @@ func NewHTTPExecuter(options *HTTPOptions) (*HTTPExecuter, error) {
return executer, nil return executer, nil
} }
// GotResults returns true if there were any results for the executer
func (e *HTTPExecuter) GotResults() bool {
if atomic.LoadUint32(&e.results) == 0 {
return false
}
return true
}
// ExecuteHTTP executes the HTTP request on a URL // ExecuteHTTP executes the HTTP request on a URL
func (e *HTTPExecuter) ExecuteHTTP(URL string) (result Result) { func (e *HTTPExecuter) ExecuteHTTP(URL string) (result Result) {
result.Matches = make(map[string]interface{}) result.Matches = make(map[string]interface{})
result.Extractions = make(map[string]interface{}) result.Extractions = make(map[string]interface{})
dynamicvalues := make(map[string]string) dynamicvalues := make(map[string]string)
// Compile each request for the template based on the URL
compiledRequest, err := e.httpRequest.MakeHTTPRequest(URL) // Requests defined via Model
for e.bulkHttpRequest.Next() {
httpRequest, err := e.bulkHttpRequest.MakeHTTPRequest(URL, e.bulkHttpRequest.Current())
if err != nil { if err != nil {
result.Error = errors.Wrap(err, "could not make http request") result.Error = errors.Wrap(err, "could not make http request")
return return
} }
// Send the request to the target servers e.handleHTTP(URL, httpRequest, dynamicvalues, &result)
mainLoop:
for compiledRequest := range compiledRequest { e.bulkHttpRequest.Increment()
if compiledRequest.Error != nil {
result.Error = errors.Wrap(err, "could not make http request")
return
} }
e.setCustomHeaders(compiledRequest)
e.setDynamicValues(compiledRequest, dynamicvalues) gologger.Verbosef("Sent HTTP request to %s\n", "http-request", URL)
req := compiledRequest.Request
return
}
func (e *HTTPExecuter) handleHTTP(URL string, request *requests.HttpRequest, dynamicvalues map[string]string, result *Result) error {
e.setCustomHeaders(request)
e.setDynamicValues(request, dynamicvalues)
req := request.Request
if e.debug { if e.debug {
gologger.Infof("Dumped HTTP request for %s (%s)\n\n", URL, e.template.ID) gologger.Infof("Dumped HTTP request for %s (%s)\n\n", URL, e.template.ID)
dumpedRequest, err := httputil.DumpRequest(req.Request, true) dumpedRequest, err := httputil.DumpRequest(req.Request, true)
if err != nil { if err != nil {
result.Error = errors.Wrap(err, "could not make http request") return errors.Wrap(err, "could not make http request")
return
} }
fmt.Fprintf(os.Stderr, "%s", string(dumpedRequest)) fmt.Fprintf(os.Stderr, "%s", string(dumpedRequest))
} }
@ -144,57 +139,53 @@ mainLoop:
resp.Body.Close() resp.Body.Close()
} }
gologger.Warningf("Could not do request: %s\n", err) gologger.Warningf("Could not do request: %s\n", err)
continue
} }
if e.debug { if e.debug {
gologger.Infof("Dumped HTTP response for %s (%s)\n\n", URL, e.template.ID) gologger.Infof("Dumped HTTP response for %s (%s)\n\n", URL, e.template.ID)
dumpedResponse, err := httputil.DumpResponse(resp, true) dumpedResponse, err := httputil.DumpResponse(resp, true)
if err != nil { if err != nil {
result.Error = errors.Wrap(err, "could not dump http response")
return
}
fmt.Fprintf(os.Stderr, "%s\n", string(dumpedResponse)) fmt.Fprintf(os.Stderr, "%s\n", string(dumpedResponse))
return errors.Wrap(err, "could not dump http response")
}
} }
data, err := ioutil.ReadAll(resp.Body) data, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
io.Copy(ioutil.Discard, resp.Body) io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close() resp.Body.Close()
result.Error = errors.Wrap(err, "could not read http body") return errors.Wrap(err, "could not read http body")
return
} }
resp.Body.Close() resp.Body.Close()
// net/http doesn't automatically decompress the response body if an encoding has been specified by the user in the request // net/http doesn't automatically decompress the response body if an encoding has been specified by the user in the request
// so in case we have to manually do it // so in case we have to manually do it
data, err = requests.HandleDecompression(compiledRequest.Request, data) data, err = requests.HandleDecompression(req, data)
if err != nil { if err != nil {
result.Error = errors.Wrap(err, "could not decompress http body") return errors.Wrap(err, "could not decompress http body")
return
} }
// Convert response body from []byte to string with zero copy // Convert response body from []byte to string with zero copy
body := unsafeToString(data) body := unsafeToString(data)
headers := headersToString(resp.Header) headers := headersToString(resp.Header)
matcherCondition := e.httpRequest.GetMatchersCondition() matcherCondition := e.bulkHttpRequest.GetMatchersCondition()
for _, matcher := range e.httpRequest.Matchers { for _, matcher := range e.bulkHttpRequest.Matchers {
// Check if the matcher matched // Check if the matcher matched
if !matcher.Match(resp, body, headers) { if !matcher.Match(resp, body, headers) {
// If the condition is AND we haven't matched, try next request. // If the condition is AND we haven't matched, try next request.
if matcherCondition == matchers.ANDCondition { if matcherCondition == matchers.ANDCondition {
continue mainLoop return nil
} }
} else { } else {
// If the matcher has matched, and its an OR // If the matcher has matched, and its an OR
// write the first output then move to next matcher. // write the first output then move to next matcher.
if matcherCondition == matchers.ORCondition && len(e.httpRequest.Extractors) == 0 { if matcherCondition == matchers.ORCondition && len(e.bulkHttpRequest.Extractors) == 0 {
result.Matches[matcher.Name] = nil result.Matches[matcher.Name] = nil
// probably redundant but ensures we snapshot current payload values when matchers are valid // probably redundant but ensures we snapshot current payload values when matchers are valid
result.Meta = compiledRequest.Meta result.Meta = request.Meta
e.writeOutputHTTP(compiledRequest, matcher, nil) e.writeOutputHTTP(request, matcher, nil)
atomic.CompareAndSwapUint32(&e.results, 0, 1) e.Results = true
} }
} }
} }
@ -202,7 +193,7 @@ mainLoop:
// All matchers have successfully completed so now start with the // All matchers have successfully completed so now start with the
// next task which is extraction of input from matchers. // next task which is extraction of input from matchers.
var extractorResults []string var extractorResults []string
for _, extractor := range e.httpRequest.Extractors { for _, extractor := range e.bulkHttpRequest.Extractors {
for match := range extractor.Extract(resp, body, headers) { for match := range extractor.Extract(resp, body, headers) {
if _, ok := dynamicvalues[extractor.Name]; !ok { if _, ok := dynamicvalues[extractor.Name]; !ok {
dynamicvalues[extractor.Name] = match dynamicvalues[extractor.Name] = match
@ -210,28 +201,25 @@ mainLoop:
extractorResults = append(extractorResults, match) extractorResults = append(extractorResults, match)
} }
// probably redundant but ensures we snapshot current payload values when extractors are valid // probably redundant but ensures we snapshot current payload values when extractors are valid
result.Meta = compiledRequest.Meta result.Meta = request.Meta
result.Extractions[extractor.Name] = extractorResults result.Extractions[extractor.Name] = extractorResults
} }
// Write a final string of output if matcher type is // Write a final string of output if matcher type is
// AND or if we have extractors for the mechanism too. // AND or if we have extractors for the mechanism too.
if len(e.httpRequest.Extractors) > 0 || matcherCondition == matchers.ANDCondition { if len(e.bulkHttpRequest.Extractors) > 0 || matcherCondition == matchers.ANDCondition {
e.writeOutputHTTP(compiledRequest, nil, extractorResults) e.writeOutputHTTP(request, nil, extractorResults)
atomic.CompareAndSwapUint32(&e.results, 0, 1) e.Results = true
}
} }
gologger.Verbosef("Sent HTTP request to %s\n", "http-request", URL) return nil
return
} }
// Close closes the http executer for a template. // Close closes the http executer for a template.
func (e *HTTPExecuter) Close() { func (e *HTTPExecuter) Close() {
e.outputMutex.Lock() e.outputMutex.Lock()
defer e.outputMutex.Unlock()
e.writer.Flush() e.writer.Flush()
e.outputMutex.Unlock()
} }
// makeHTTPClient creates a http client // makeHTTPClient creates a http client
@ -239,8 +227,8 @@ func makeHTTPClient(proxyURL *url.URL, options *HTTPOptions) *retryablehttp.Clie
retryablehttpOptions := retryablehttp.DefaultOptionsSpraying retryablehttpOptions := retryablehttp.DefaultOptionsSpraying
retryablehttpOptions.RetryWaitMax = 10 * time.Second retryablehttpOptions.RetryWaitMax = 10 * time.Second
retryablehttpOptions.RetryMax = options.Retries retryablehttpOptions.RetryMax = options.Retries
followRedirects := options.HTTPRequest.Redirects followRedirects := options.BulkHttpRequest.Redirects
maxRedirects := options.HTTPRequest.MaxRedirects maxRedirects := options.BulkHttpRequest.MaxRedirects
transport := &http.Transport{ transport := &http.Transport{
MaxIdleConnsPerHost: -1, MaxIdleConnsPerHost: -1,
@ -296,7 +284,7 @@ func makeCheckRedirectFunc(followRedirects bool, maxRedirects int) checkRedirect
} }
} }
func (e *HTTPExecuter) setCustomHeaders(r *requests.CompiledHTTP) { func (e *HTTPExecuter) setCustomHeaders(r *requests.HttpRequest) {
for _, customHeader := range e.customHeaders { for _, customHeader := range e.customHeaders {
// This should be pre-computed somewhere and done only once // This should be pre-computed somewhere and done only once
tokens := strings.Split(customHeader, ":") tokens := strings.Split(customHeader, ":")
@ -313,7 +301,7 @@ func (e *HTTPExecuter) setCustomHeaders(r *requests.CompiledHTTP) {
} }
// for now supports only headers // for now supports only headers
func (e *HTTPExecuter) setDynamicValues(r *requests.CompiledHTTP, dynamicValues map[string]string) { func (e *HTTPExecuter) setDynamicValues(r *requests.HttpRequest, dynamicValues map[string]string) {
for dk, dv := range dynamicValues { for dk, dv := range dynamicValues {
// replace within header values // replace within header values
for k, v := range r.Request.Header { for k, v := range r.Request.Header {

View File

@ -10,7 +10,7 @@ import (
) )
// writeOutputHTTP writes http output to streams // writeOutputHTTP writes http output to streams
func (e *HTTPExecuter) writeOutputHTTP(req *requests.CompiledHTTP, matcher *matchers.Matcher, extractorResults []string) { func (e *HTTPExecuter) writeOutputHTTP(req *requests.HttpRequest, matcher *matchers.Matcher, extractorResults []string) {
URL := req.Request.URL.String() URL := req.Request.URL.String()
if e.jsonOutput { if e.jsonOutput {

View File

@ -16,8 +16,8 @@ import (
retryablehttp "github.com/projectdiscovery/retryablehttp-go" retryablehttp "github.com/projectdiscovery/retryablehttp-go"
) )
// HTTPRequest contains a request to be made from a template // BulkHTTPRequest contains a request to be made from a template
type HTTPRequest struct { type BulkHTTPRequest struct {
Name string `yaml:"Name,omitempty"` Name string `yaml:"Name,omitempty"`
// AttackType is the attack type // AttackType is the attack type
// Sniper, PitchFork and ClusterBomb. Default is Sniper // Sniper, PitchFork and ClusterBomb. Default is Sniper
@ -53,30 +53,36 @@ type HTTPRequest struct {
MaxRedirects int `yaml:"max-redirects,omitempty"` MaxRedirects int `yaml:"max-redirects,omitempty"`
// Raw contains raw requests // Raw contains raw requests
Raw []string `yaml:"raw,omitempty"` Raw []string `yaml:"raw,omitempty"`
positionPath int
positionRaw int
generator func(payloads map[string][]string) (out chan map[string]interface{})
currentPayloads map[string]interface{}
basePayloads map[string][]string
generatorChan chan map[string]interface{}
currentGeneratorValue map[string]interface{}
} }
// GetMatchersCondition returns the condition for the matcher // GetMatchersCondition returns the condition for the matcher
func (r *HTTPRequest) GetMatchersCondition() matchers.ConditionType { func (r *BulkHTTPRequest) GetMatchersCondition() matchers.ConditionType {
return r.matchersCondition return r.matchersCondition
} }
// SetMatchersCondition sets the condition for the matcher // SetMatchersCondition sets the condition for the matcher
func (r *HTTPRequest) SetMatchersCondition(condition matchers.ConditionType) { func (r *BulkHTTPRequest) SetMatchersCondition(condition matchers.ConditionType) {
r.matchersCondition = condition r.matchersCondition = condition
} }
// GetAttackType returns the attack // GetAttackType returns the attack
func (r *HTTPRequest) GetAttackType() generators.Type { func (r *BulkHTTPRequest) GetAttackType() generators.Type {
return r.attackType return r.attackType
} }
// SetAttackType sets the attack // SetAttackType sets the attack
func (r *HTTPRequest) SetAttackType(attack generators.Type) { func (r *BulkHTTPRequest) SetAttackType(attack generators.Type) {
r.attackType = attack r.attackType = attack
} }
// MakeHTTPRequest creates a *http.Request from a request configuration func (r *BulkHTTPRequest) MakeHTTPRequest(baseURL string, data string) (*HttpRequest, error) {
func (r *HTTPRequest) MakeHTTPRequest(baseURL string) (chan *CompiledHTTP, error) {
parsed, err := url.Parse(baseURL) parsed, err := url.Parse(baseURL)
if err != nil { if err != nil {
return nil, err return nil, err
@ -88,60 +94,52 @@ func (r *HTTPRequest) MakeHTTPRequest(baseURL string) (chan *CompiledHTTP, error
"Hostname": hostname, "Hostname": hostname,
} }
if len(r.Raw) > 0 { // if data contains \n it's a raw request
return r.makeHTTPRequestFromRaw(baseURL, values) if strings.Contains(data, "\n") {
return r.makeHTTPRequestFromRaw(baseURL, data, values)
} }
return r.makeHTTPRequestFromModel(baseURL, values) return r.makeHTTPRequestFromModel(baseURL, data, values)
} }
// MakeHTTPRequestFromModel creates a *http.Request from a request template // MakeHTTPRequestFromModel creates a *http.Request from a request template
func (r *HTTPRequest) makeHTTPRequestFromModel(baseURL string, values map[string]interface{}) (requests chan *CompiledHTTP, err error) { func (r *BulkHTTPRequest) makeHTTPRequestFromModel(baseURL string, data string, values map[string]interface{}) (*HttpRequest, error) {
requests = make(chan *CompiledHTTP)
// request generator
go func() {
defer close(requests)
for _, path := range r.Path {
// process base request
replacer := newReplacer(values) replacer := newReplacer(values)
URL := replacer.Replace(data)
// Replace the dynamic variables in the URL if any
URL := replacer.Replace(path)
// Build a request on the specified URL // Build a request on the specified URL
req, err := http.NewRequest(r.Method, URL, nil) req, err := http.NewRequest(r.Method, URL, nil)
if err != nil { if err != nil {
requests <- &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
return
} }
request, err := r.fillRequest(req, values) request, err := r.fillRequest(req, values)
if err != nil { if err != nil {
requests <- &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
return
} }
requests <- &CompiledHTTP{Request: request, Error: nil, Meta: nil} return &HttpRequest{Request: request}, nil
} }
}()
return func (r *BulkHTTPRequest) StartGenerator() {
r.generatorChan = r.generator(r.basePayloads)
}
func (r *BulkHTTPRequest) PickOne() {
var ok bool
r.currentGeneratorValue, ok = <-r.generatorChan
if !ok {
r.generator = nil
}
} }
// makeHTTPRequestFromRaw creates a *http.Request from a raw request // makeHTTPRequestFromRaw creates a *http.Request from a raw request
func (r *HTTPRequest) makeHTTPRequestFromRaw(baseURL string, values map[string]interface{}) (requests chan *CompiledHTTP, err error) { func (r *BulkHTTPRequest) makeHTTPRequestFromRaw(baseURL string, data string, values map[string]interface{}) (*HttpRequest, error) {
requests = make(chan *CompiledHTTP)
// request generator
go func() {
defer close(requests)
for _, raw := range r.Raw {
// Add trailing line // Add trailing line
raw += "\n" data += "\n"
if len(r.Payloads) > 0 { if len(r.Payloads) > 0 {
basePayloads := generators.LoadPayloads(r.Payloads) if r.generator == nil {
r.basePayloads = generators.LoadPayloads(r.Payloads)
generatorFunc := generators.SniperGenerator generatorFunc := generators.SniperGenerator
switch r.attackType { switch r.attackType {
case generators.PitchFork: case generators.PitchFork:
@ -149,58 +147,49 @@ func (r *HTTPRequest) makeHTTPRequestFromRaw(baseURL string, values map[string]i
case generators.ClusterBomb: case generators.ClusterBomb:
generatorFunc = generators.ClusterbombGenerator generatorFunc = generators.ClusterbombGenerator
} }
r.generator = generatorFunc
r.StartGenerator()
}
for genValues := range generatorFunc(basePayloads) { r.PickOne()
compiledHTTP := r.handleRawWithPaylods(raw, baseURL, values, genValues)
requests <- compiledHTTP return r.handleRawWithPaylods(data, baseURL, values, r.currentGeneratorValue)
if compiledHTTP.Error != nil {
return
} }
}
} else {
// otherwise continue with normal flow // otherwise continue with normal flow
compiledHTTP := r.handleSimpleRaw(raw, baseURL, values) return r.handleSimpleRaw(data, baseURL, values)
requests <- compiledHTTP
if compiledHTTP.Error != nil {
return
}
}
}
}()
return requests, nil
} }
func (r *HTTPRequest) handleSimpleRaw(raw string, baseURL string, values map[string]interface{}) *CompiledHTTP { func (r *BulkHTTPRequest) handleSimpleRaw(raw string, baseURL string, values map[string]interface{}) (*HttpRequest, error) {
// base request // base request
replacer := newReplacer(values) replacer := newReplacer(values)
// Replace the dynamic variables in the request if any // Replace the dynamic variables in the request if any
raw = replacer.Replace(raw) raw = replacer.Replace(raw)
compiledRequest, err := r.parseRawRequest(raw, baseURL) rawRequest, err := r.parseRawRequest(raw, baseURL)
if err != nil { if err != nil {
return &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
} }
req, err := http.NewRequest(compiledRequest.Method, compiledRequest.FullURL, strings.NewReader(compiledRequest.Data)) req, err := http.NewRequest(rawRequest.Method, rawRequest.FullURL, strings.NewReader(rawRequest.Data))
if err != nil { if err != nil {
return &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
} }
// copy headers // copy headers
for key, value := range compiledRequest.Headers { for key, value := range rawRequest.Headers {
req.Header[key] = []string{value} req.Header[key] = []string{value}
} }
request, err := r.fillRequest(req, values) request, err := r.fillRequest(req, values)
if err != nil { if err != nil {
return &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
} }
return &CompiledHTTP{Request: request, Error: nil, Meta: nil} return &HttpRequest{Request: request}, nil
} }
func (r *HTTPRequest) handleRawWithPaylods(raw string, baseURL string, values, genValues map[string]interface{}) *CompiledHTTP { func (r *BulkHTTPRequest) handleRawWithPaylods(raw string, baseURL string, values, genValues map[string]interface{}) (*HttpRequest, error) {
baseValues := generators.CopyMap(values) baseValues := generators.CopyMap(values)
finValues := generators.MergeMaps(baseValues, genValues) finValues := generators.MergeMaps(baseValues, genValues)
@ -218,11 +207,11 @@ func (r *HTTPRequest) handleRawWithPaylods(raw string, baseURL string, values, g
expr := generators.TrimDelimiters(match) expr := generators.TrimDelimiters(match)
compiled, err := govaluate.NewEvaluableExpressionWithFunctions(expr, generators.HelperFunctions()) compiled, err := govaluate.NewEvaluableExpressionWithFunctions(expr, generators.HelperFunctions())
if err != nil { if err != nil {
return &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
} }
result, err := compiled.Evaluate(finValues) result, err := compiled.Evaluate(finValues)
if err != nil { if err != nil {
return &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
} }
dynamicValues[expr] = result dynamicValues[expr] = result
} }
@ -234,12 +223,12 @@ func (r *HTTPRequest) handleRawWithPaylods(raw string, baseURL string, values, g
compiledRequest, err := r.parseRawRequest(raw, baseURL) compiledRequest, err := r.parseRawRequest(raw, baseURL)
if err != nil { if err != nil {
return &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
} }
req, err := http.NewRequest(compiledRequest.Method, compiledRequest.FullURL, strings.NewReader(compiledRequest.Data)) req, err := http.NewRequest(compiledRequest.Method, compiledRequest.FullURL, strings.NewReader(compiledRequest.Data))
if err != nil { if err != nil {
return &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
} }
// copy headers // copy headers
@ -249,13 +238,13 @@ func (r *HTTPRequest) handleRawWithPaylods(raw string, baseURL string, values, g
request, err := r.fillRequest(req, values) request, err := r.fillRequest(req, values)
if err != nil { if err != nil {
return &CompiledHTTP{Request: nil, Error: err, Meta: nil} return nil, err
} }
return &CompiledHTTP{Request: request, Error: nil, Meta: genValues} return &HttpRequest{Request: request, Meta: genValues}, nil
} }
func (r *HTTPRequest) fillRequest(req *http.Request, values map[string]interface{}) (*retryablehttp.Request, error) { func (r *BulkHTTPRequest) fillRequest(req *http.Request, values map[string]interface{}) (*retryablehttp.Request, error) {
req.Header.Set("Connection", "close") req.Header.Set("Connection", "close")
req.Close = true req.Close = true
replacer := newReplacer(values) replacer := newReplacer(values)
@ -290,10 +279,8 @@ func (r *HTTPRequest) fillRequest(req *http.Request, values map[string]interface
return retryablehttp.FromRequest(req) return retryablehttp.FromRequest(req)
} }
// CompiledHTTP contains Generated HTTP Request or error type HttpRequest struct {
type CompiledHTTP struct {
Request *retryablehttp.Request Request *retryablehttp.Request
Error error
Meta map[string]interface{} Meta map[string]interface{}
} }
@ -311,7 +298,7 @@ func (c *CustomHeaders) Set(value string) error {
return nil return nil
} }
type compiledRawRequest struct { type RawRequest struct {
FullURL string FullURL string
Method string Method string
Path string Path string
@ -320,10 +307,10 @@ type compiledRawRequest struct {
} }
// parseRawRequest parses the raw request as supplied by the user // parseRawRequest parses the raw request as supplied by the user
func (r *HTTPRequest) parseRawRequest(request string, baseURL string) (*compiledRawRequest, error) { func (r *BulkHTTPRequest) parseRawRequest(request string, baseURL string) (*RawRequest, error) {
reader := bufio.NewReader(strings.NewReader(request)) reader := bufio.NewReader(strings.NewReader(request))
rawRequest := compiledRawRequest{ rawRequest := RawRequest{
Headers: make(map[string]string), Headers: make(map[string]string),
} }
@ -406,3 +393,41 @@ func (r *HTTPRequest) parseRawRequest(request string, baseURL string) (*compiled
rawRequest.Data = string(b) rawRequest.Data = string(b)
return &rawRequest, nil return &rawRequest, nil
} }
func (r *BulkHTTPRequest) Next() bool {
if r.positionPath+r.positionRaw >= len(r.Path)+len(r.Raw) {
return false
}
return true
}
func (r *BulkHTTPRequest) Position() int {
return r.positionPath + r.positionRaw
}
func (r *BulkHTTPRequest) Reset() {
r.positionPath = 0
r.positionRaw = 0
}
func (r *BulkHTTPRequest) Current() string {
if r.positionPath <= len(r.Path) && len(r.Path) != 0 && r.positionRaw == 0 {
return r.Path[r.positionPath]
}
return r.Raw[r.positionRaw]
}
func (r *BulkHTTPRequest) Total() int {
return len(r.Path) + len(r.Raw)
}
func (r *BulkHTTPRequest) Increment() int {
if r.positionPath <= len(r.Path) && len(r.Path) != 0 && r.positionRaw == 0 {
r.positionPath++
return r.positionPath
}
// if we have payloads increment only when the generators are done
if r.generator == nil {
r.positionRaw++
}
return r.positionPath + r.positionRaw
}

View File

@ -27,12 +27,12 @@ func Parse(file string) (*Template, error) {
defer f.Close() defer f.Close()
// If no requests, and it is also not a workflow, return error. // If no requests, and it is also not a workflow, return error.
if len(template.RequestsHTTP)+len(template.RequestsDNS) <= 0 { if len(template.BulkRequestsHTTP)+len(template.RequestsDNS) <= 0 {
return nil, errors.New("No requests defined") return nil, errors.New("No requests defined")
} }
// Compile the matchers and the extractors for http requests // Compile the matchers and the extractors for http requests
for _, request := range template.RequestsHTTP { for _, request := range template.BulkRequestsHTTP {
// Get the condition between the matchers // Get the condition between the matchers
condition, ok := matchers.ConditionTypes[request.MatchersCondition] condition, ok := matchers.ConditionTypes[request.MatchersCondition]
if !ok { if !ok {

View File

@ -10,9 +10,9 @@ type Template struct {
ID string `yaml:"id"` ID string `yaml:"id"`
// Info contains information about the template // Info contains information about the template
Info Info `yaml:"info"` Info Info `yaml:"info"`
// RequestHTTP contains the http request to make in the template // BulkRequestsHTTP contains the http request to make in the template
RequestsHTTP []*requests.HTTPRequest `yaml:"requests,omitempty"` BulkRequestsHTTP []*requests.BulkHTTPRequest `yaml:"requests,omitempty"`
// RequestDNS contains the dns request to make in the template // RequestsDNS contains the dns request to make in the template
RequestsDNS []*requests.DNSRequest `yaml:"dns,omitempty"` RequestsDNS []*requests.DNSRequest `yaml:"dns,omitempty"`
} }

View File

@ -53,12 +53,12 @@ func (n *NucleiVar) Call(args ...tengo.Object) (ret tengo.Object, err error) {
var gotResult bool var gotResult bool
for _, template := range n.Templates { for _, template := range n.Templates {
if template.HTTPOptions != nil { if template.HTTPOptions != nil {
for _, request := range template.HTTPOptions.Template.RequestsHTTP { for _, request := range template.HTTPOptions.Template.BulkRequestsHTTP {
// apply externally supplied payloads if any // apply externally supplied payloads if any
request.Headers = generators.MergeMapsWithStrings(request.Headers, headers) request.Headers = generators.MergeMapsWithStrings(request.Headers, headers)
// apply externally supplied payloads if any // apply externally supplied payloads if any
request.Payloads = generators.MergeMaps(request.Payloads, externalVars) request.Payloads = generators.MergeMaps(request.Payloads, externalVars)
template.HTTPOptions.HTTPRequest = request template.HTTPOptions.BulkHttpRequest = request
httpExecuter, err := executer.NewHTTPExecuter(template.HTTPOptions) httpExecuter, err := executer.NewHTTPExecuter(template.HTTPOptions)
if err != nil { if err != nil {
gologger.Warningf("Could not compile request for template '%s': %s\n", template.HTTPOptions.Template.ID, err) gologger.Warningf("Could not compile request for template '%s': %s\n", template.HTTPOptions.Template.ID, err)
@ -70,7 +70,7 @@ func (n *NucleiVar) Call(args ...tengo.Object) (ret tengo.Object, err error) {
continue continue
} }
if httpExecuter.GotResults() { if httpExecuter.Results {
gotResult = true gotResult = true
n.addResults(&result) n.addResults(&result)
} }
@ -87,7 +87,7 @@ func (n *NucleiVar) Call(args ...tengo.Object) (ret tengo.Object, err error) {
continue continue
} }
if dnsExecuter.GotResults() { if dnsExecuter.Results {
gotResult = true gotResult = true
n.addResults(&result) n.addResults(&result)
} }