mirror of https://github.com/daffainfo/nuclei.git
begin of work on fuzzing - only working for raw requests with payload (TODO code cleanup)
parent
443140a52f
commit
44821e6b77
1
go.mod
1
go.mod
|
@ -5,6 +5,7 @@ go 1.14
|
|||
require (
|
||||
github.com/Knetic/govaluate v3.0.0+incompatible
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535
|
||||
github.com/karrick/godirwalk v1.15.6
|
||||
github.com/miekg/dns v1.1.29
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/projectdiscovery/gologger v1.0.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -4,6 +4,8 @@ github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8L
|
|||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY=
|
||||
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/karrick/godirwalk v1.15.6 h1:Yf2mmR8TJy+8Fa0SuQVto5SYap6IF7lNVX4Jdl8G1qA=
|
||||
github.com/karrick/godirwalk v1.15.6/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/miekg/dns v1.1.29 h1:xHBEhR+t5RzcFJjBLJlax2daXOrTYtr9z4WdKEfWFzg=
|
||||
|
|
|
@ -78,7 +78,7 @@ func (e *HTTPExecutor) ExecuteHTTP(URL string) error {
|
|||
|
||||
// Send the request to the target servers
|
||||
mainLoop:
|
||||
for _, req := range compiledRequest {
|
||||
for req := range compiledRequest {
|
||||
resp, err := e.httpClient.Do(req)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package generators
|
||||
|
||||
// Type is type of attack
|
||||
type Type int
|
||||
|
||||
const (
|
||||
// Sniper attack - each variable replaced with values at a time
|
||||
Sniper Type = iota + 1
|
||||
// PitchFork attack - Each variable replaced with positional value in multiple wordlists
|
||||
PitchFork
|
||||
// ClusterBomb attack - Generate all possible combinations of values
|
||||
ClusterBomb
|
||||
)
|
||||
|
||||
// AttackTypes is an table for conversion of attack type from string.
|
||||
var AttackTypes = map[string]Type{
|
||||
"sniper": Sniper,
|
||||
"pitchfork": PitchFork,
|
||||
"clusterbomb": ClusterBomb,
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package generators
|
||||
|
||||
// ClusterbombGenerator Attack - Generate all possible combinations from an input map with all values listed
|
||||
// as slices of the same size
|
||||
func ClusterbombGenerator(payloads map[string][]string) (out chan map[string]interface{}) {
|
||||
out = make(chan map[string]interface{})
|
||||
|
||||
// generator
|
||||
go func() {
|
||||
defer close(out)
|
||||
var order []string
|
||||
var parts [][]string
|
||||
for name, wordlist := range payloads {
|
||||
order = append(order, name)
|
||||
parts = append(parts, wordlist)
|
||||
}
|
||||
|
||||
var n = 1
|
||||
for _, ar := range parts {
|
||||
n *= len(ar)
|
||||
}
|
||||
|
||||
var at = make([]int, len(parts))
|
||||
loop:
|
||||
for {
|
||||
// increment position counters
|
||||
for i := len(parts) - 1; i >= 0; i-- {
|
||||
if at[i] > 0 && at[i] >= len(parts[i]) {
|
||||
if i == 0 || (i == 1 && at[i-1] == len(parts[0])-1) {
|
||||
break loop
|
||||
}
|
||||
at[i] = 0
|
||||
at[i-1]++
|
||||
}
|
||||
}
|
||||
// construct permutation
|
||||
item := make(map[string]interface{})
|
||||
for i, ar := range parts {
|
||||
var p = at[i]
|
||||
if p >= 0 && p < len(ar) {
|
||||
item[order[i]] = ar[p]
|
||||
}
|
||||
}
|
||||
out <- item
|
||||
at[len(parts)-1]++
|
||||
}
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package generators
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"html"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Knetic/govaluate"
|
||||
)
|
||||
|
||||
// HelperFunctions contains the dsl functions
|
||||
func HelperFunctions() (functions map[string]govaluate.ExpressionFunction) {
|
||||
functions = make(map[string]govaluate.ExpressionFunction)
|
||||
// strings
|
||||
functions["len"] = func(args ...interface{}) (interface{}, error) {
|
||||
length := len(args[0].(string))
|
||||
return (float64)(length), nil
|
||||
}
|
||||
functions["toupper"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.ToUpper(args[0].(string)), nil
|
||||
}
|
||||
functions["tolower"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.ToLower(args[0].(string)), nil
|
||||
}
|
||||
functions["replace"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.Replace(args[0].(string), args[1].(string), args[2].(string), -1), nil
|
||||
}
|
||||
functions["trim"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.Trim(args[0].(string), args[2].(string)), nil
|
||||
}
|
||||
functions["trimleft"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimLeft(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
functions["trimright"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimRight(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
functions["trimspace"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimSpace(args[0].(string)), nil
|
||||
}
|
||||
functions["trimprefix"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimPrefix(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
functions["trimsuffix"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimSuffix(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
functions["reverse"] = func(args ...interface{}) (interface{}, error) {
|
||||
return reverseString(args[0].(string)), nil
|
||||
}
|
||||
// encoding
|
||||
functions["base64"] = func(args ...interface{}) (interface{}, error) {
|
||||
sEnc := base64.StdEncoding.EncodeToString([]byte(args[0].(string)))
|
||||
return sEnc, nil
|
||||
}
|
||||
functions["base64_decode"] = func(args ...interface{}) (interface{}, error) {
|
||||
sEnc := base64.StdEncoding.EncodeToString([]byte(args[0].(string)))
|
||||
return sEnc, nil
|
||||
}
|
||||
functions["url_encode"] = func(args ...interface{}) (interface{}, error) {
|
||||
return url.PathEscape(args[0].(string)), nil
|
||||
}
|
||||
functions["url_decode"] = func(args ...interface{}) (interface{}, error) {
|
||||
return url.PathUnescape(args[0].(string))
|
||||
}
|
||||
functions["hex_encode"] = func(args ...interface{}) (interface{}, error) {
|
||||
return hex.EncodeToString([]byte(args[0].(string))), nil
|
||||
}
|
||||
functions["hex_decode"] = func(args ...interface{}) (interface{}, error) {
|
||||
hx, _ := hex.DecodeString(args[0].(string))
|
||||
return string(hx), nil
|
||||
}
|
||||
functions["html_escape"] = func(args ...interface{}) (interface{}, error) {
|
||||
return html.EscapeString(args[0].(string)), nil
|
||||
}
|
||||
functions["html_unescape"] = func(args ...interface{}) (interface{}, error) {
|
||||
return html.UnescapeString(args[0].(string)), nil
|
||||
}
|
||||
// hashing
|
||||
functions["md5"] = func(args ...interface{}) (interface{}, error) {
|
||||
hash := md5.Sum([]byte(args[0].(string)))
|
||||
return hex.EncodeToString(hash[:]), nil
|
||||
}
|
||||
functions["sha256"] = func(args ...interface{}) (interface{}, error) {
|
||||
return sha256.Sum256([]byte(args[0].(string))), nil
|
||||
}
|
||||
// search
|
||||
functions["contains"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.Contains(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
functions["regex"] = func(args ...interface{}) (interface{}, error) {
|
||||
compiled, err := regexp.Compile(args[0].(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return compiled.MatchString(args[1].(string)), nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package generators
|
||||
|
||||
// PitchforkGenerator Attack - Generate positional combinations from an input map with all values listed
|
||||
// as slices of the same size
|
||||
func PitchforkGenerator(payloads map[string][]string) (out chan map[string]interface{}) {
|
||||
out = make(chan map[string]interface{})
|
||||
|
||||
size := 0
|
||||
|
||||
// check if all wordlists have the same size
|
||||
for _, wordlist := range payloads {
|
||||
if size == 0 {
|
||||
size = len(wordlist)
|
||||
}
|
||||
|
||||
if len(wordlist) != size {
|
||||
//set size = 0 and exit the cycle
|
||||
size = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// generator
|
||||
go func() {
|
||||
defer close(out)
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
element := make(map[string]interface{})
|
||||
for name, wordlist := range payloads {
|
||||
element[name] = wordlist[i]
|
||||
}
|
||||
|
||||
out <- element
|
||||
}
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package generators
|
||||
|
||||
// SniperGenerator Attack - Generate sequential combinations
|
||||
func SniperGenerator(payloads map[string][]string) (out chan map[string]interface{}) {
|
||||
out = make(chan map[string]interface{})
|
||||
|
||||
// generator
|
||||
go func() {
|
||||
defer close(out)
|
||||
|
||||
for name, wordlist := range payloads {
|
||||
for _, value := range wordlist {
|
||||
element := CopyMapWithDefaultValue(payloads, "")
|
||||
element[name] = value
|
||||
out <- element
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return out
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package generators
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// LoadWordlists creating proper data structure
|
||||
func LoadWordlists(payloads map[string]string) map[string][]string {
|
||||
wordlists := make(map[string][]string)
|
||||
// load all wordlists
|
||||
for name, filepath := range payloads {
|
||||
wordlists[name] = LoadFile(filepath)
|
||||
}
|
||||
|
||||
return wordlists
|
||||
}
|
||||
|
||||
// LoadFile into slice of strings
|
||||
func LoadFile(filepath string) (lines []string) {
|
||||
for line := range StreamFile(filepath) {
|
||||
lines = append(lines, line)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// StreamFile content to a chan
|
||||
func StreamFile(filepath string) (content chan string) {
|
||||
content = make(chan string)
|
||||
|
||||
go func() {
|
||||
defer close(content)
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// yql filter applied
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
content <- scanner.Text()
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// MergeMaps into a new one
|
||||
func MergeMaps(m1, m2 map[string]interface{}) (m map[string]interface{}) {
|
||||
m = make(map[string]interface{})
|
||||
for k, v := range m1 {
|
||||
m[k] = v
|
||||
}
|
||||
for k, v := range m2 {
|
||||
m[k] = v
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func reverseString(s string) string {
|
||||
runes := []rune(s)
|
||||
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
|
||||
runes[i], runes[j] = runes[j], runes[i]
|
||||
}
|
||||
return string(runes)
|
||||
}
|
||||
|
||||
// CopyMap creates a new copy of an existing map
|
||||
func CopyMap(originalMap map[string]interface{}) map[string]interface{} {
|
||||
newMap := make(map[string]interface{})
|
||||
for key, value := range originalMap {
|
||||
newMap[key] = value
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// CopyMapWithDefaultValue creates a new copy of an existing map and set a default value
|
||||
func CopyMapWithDefaultValue(originalMap map[string][]string, defaultValue interface{}) map[string]interface{} {
|
||||
newMap := make(map[string]interface{})
|
||||
for key := range originalMap {
|
||||
newMap[key] = defaultValue
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
// StringContainsAnyMapItem verifies is a string contains any value of a map
|
||||
func StringContainsAnyMapItem(m map[string]interface{}, s string) bool {
|
||||
for key := range m {
|
||||
if strings.Contains(s, key) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// TrimDelimiters removes trailing brackets
|
||||
func TrimDelimiters(s string) string {
|
||||
return strings.TrimSuffix(strings.TrimPrefix(s, "{{"), "}}")
|
||||
}
|
|
@ -1,15 +1,11 @@
|
|||
package matchers
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Knetic/govaluate"
|
||||
"github.com/projectdiscovery/nuclei/pkg/generators"
|
||||
)
|
||||
|
||||
// CompileMatchers performs the initial setup operation on a matcher
|
||||
|
@ -34,7 +30,7 @@ func (m *Matcher) CompileMatchers() error {
|
|||
|
||||
// Compile the dsl expressions
|
||||
for _, dsl := range m.DSL {
|
||||
compiled, err := govaluate.NewEvaluableExpressionWithFunctions(dsl, helperFunctions())
|
||||
compiled, err := govaluate.NewEvaluableExpressionWithFunctions(dsl, generators.HelperFunctions())
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not compile dsl: %s", dsl)
|
||||
}
|
||||
|
@ -63,69 +59,3 @@ func (m *Matcher) CompileMatchers() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func helperFunctions() (functions map[string]govaluate.ExpressionFunction) {
|
||||
functions = make(map[string]govaluate.ExpressionFunction)
|
||||
// strings
|
||||
functions["len"] = func(args ...interface{}) (interface{}, error) {
|
||||
length := len(args[0].(string))
|
||||
return (float64)(length), nil
|
||||
}
|
||||
functions["toupper"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.ToUpper(args[0].(string)), nil
|
||||
}
|
||||
functions["tolower"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.ToLower(args[0].(string)), nil
|
||||
}
|
||||
functions["replace"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.Replace(args[0].(string), args[1].(string), args[2].(string), -1), nil
|
||||
}
|
||||
functions["trim"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.Trim(args[0].(string), args[2].(string)), nil
|
||||
}
|
||||
functions["trimleft"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimLeft(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
functions["trimright"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimRight(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
functions["trimspace"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimSpace(args[0].(string)), nil
|
||||
}
|
||||
functions["trimprefix"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimPrefix(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
functions["trimsuffix"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.TrimSuffix(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
// encoding
|
||||
functions["base64"] = func(args ...interface{}) (interface{}, error) {
|
||||
sEnc := base64.StdEncoding.EncodeToString([]byte(args[0].(string)))
|
||||
return sEnc, nil
|
||||
}
|
||||
functions["base64_decode"] = func(args ...interface{}) (interface{}, error) {
|
||||
sEnc := base64.StdEncoding.EncodeToString([]byte(args[0].(string)))
|
||||
return sEnc, nil
|
||||
}
|
||||
// hashing
|
||||
functions["md5"] = func(args ...interface{}) (interface{}, error) {
|
||||
hash := md5.Sum([]byte(args[0].(string)))
|
||||
return hex.EncodeToString(hash[:]), nil
|
||||
}
|
||||
functions["sha256"] = func(args ...interface{}) (interface{}, error) {
|
||||
return sha256.Sum256([]byte(args[0].(string))), nil
|
||||
}
|
||||
// search
|
||||
functions["contains"] = func(args ...interface{}) (interface{}, error) {
|
||||
return strings.Contains(args[0].(string), args[1].(string)), nil
|
||||
}
|
||||
functions["regex"] = func(args ...interface{}) (interface{}, error) {
|
||||
compiled, err := regexp.Compile(args[0].(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return compiled.MatchString(args[1].(string)), nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,17 +4,28 @@ import (
|
|||
"bufio"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Knetic/govaluate"
|
||||
"github.com/projectdiscovery/nuclei/pkg/extractors"
|
||||
"github.com/projectdiscovery/nuclei/pkg/generators"
|
||||
"github.com/projectdiscovery/nuclei/pkg/matchers"
|
||||
retryablehttp "github.com/projectdiscovery/retryablehttp-go"
|
||||
)
|
||||
|
||||
// HTTPRequest contains a request to be made from a template
|
||||
type HTTPRequest struct {
|
||||
// AttackType is the attack type
|
||||
// Sniper, PitchFork and ClusterBomb. Default is Sniper
|
||||
AttackType string `yaml:"attack,omitempty"`
|
||||
// attackType is internal attack type
|
||||
attackType generators.Type
|
||||
// Path contains the path/s for the request variables
|
||||
Payloads map[string]string `yaml:"payloads,omitempty"`
|
||||
// Method is the request method, whether GET, POST, PUT, etc
|
||||
Method string `yaml:"method"`
|
||||
// Path contains the path/s for the request
|
||||
|
@ -52,8 +63,18 @@ func (r *HTTPRequest) SetMatchersCondition(condition matchers.ConditionType) {
|
|||
r.matchersCondition = condition
|
||||
}
|
||||
|
||||
// GetAttackType returns the attack
|
||||
func (r *HTTPRequest) GetAttackType() generators.Type {
|
||||
return r.attackType
|
||||
}
|
||||
|
||||
// SetAttackType sets the attack
|
||||
func (r *HTTPRequest) SetAttackType(attack generators.Type) {
|
||||
r.attackType = attack
|
||||
}
|
||||
|
||||
// MakeHTTPRequest creates a *http.Request from a request configuration
|
||||
func (r *HTTPRequest) MakeHTTPRequest(baseURL string) ([]*retryablehttp.Request, error) {
|
||||
func (r *HTTPRequest) MakeHTTPRequest(baseURL string) (chan *retryablehttp.Request, error) {
|
||||
parsed, err := url.Parse(baseURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -73,64 +94,159 @@ func (r *HTTPRequest) MakeHTTPRequest(baseURL string) ([]*retryablehttp.Request,
|
|||
}
|
||||
|
||||
// MakeHTTPRequestFromModel creates a *http.Request from a request template
|
||||
func (r *HTTPRequest) makeHTTPRequestFromModel(baseURL string, values map[string]interface{}) (requests []*retryablehttp.Request, err error) {
|
||||
replacer := newReplacer(values)
|
||||
for _, path := range r.Path {
|
||||
// Replace the dynamic variables in the URL if any
|
||||
URL := replacer.Replace(path)
|
||||
func (r *HTTPRequest) makeHTTPRequestFromModel(baseURL string, values map[string]interface{}) (requests chan *retryablehttp.Request, err error) {
|
||||
requests = make(chan *retryablehttp.Request)
|
||||
|
||||
// Build a request on the specified URL
|
||||
req, err := http.NewRequest(r.Method, URL, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// request generator
|
||||
go func() {
|
||||
defer close(requests)
|
||||
for _, path := range r.Path {
|
||||
// process base request
|
||||
replacer := newReplacer(values)
|
||||
|
||||
// Replace the dynamic variables in the URL if any
|
||||
URL := replacer.Replace(path)
|
||||
|
||||
// Build a request on the specified URL
|
||||
req, err := http.NewRequest(r.Method, URL, nil)
|
||||
if err != nil {
|
||||
// find a way to pass the error
|
||||
return
|
||||
}
|
||||
|
||||
request, err := r.fillRequest(req, values)
|
||||
if err != nil {
|
||||
// find a way to pass the error
|
||||
return
|
||||
}
|
||||
|
||||
requests <- request
|
||||
}
|
||||
|
||||
request, err := r.fillRequest(req, values)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
requests = append(requests, request)
|
||||
}
|
||||
}()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// makeHTTPRequestFromRaw creates a *http.Request from a raw request
|
||||
func (r *HTTPRequest) makeHTTPRequestFromRaw(baseURL string, values map[string]interface{}) (requests []*retryablehttp.Request, err error) {
|
||||
replacer := newReplacer(values)
|
||||
for _, raw := range r.Raw {
|
||||
// Add trailing line
|
||||
raw += "\n"
|
||||
func (r *HTTPRequest) makeHTTPRequestFromRaw(baseURL string, values map[string]interface{}) (requests chan *retryablehttp.Request, err error) {
|
||||
requests = make(chan *retryablehttp.Request)
|
||||
// request generator
|
||||
go func() {
|
||||
defer close(requests)
|
||||
|
||||
// Replace the dynamic variables in the URL if any
|
||||
raw = replacer.Replace(raw)
|
||||
for _, raw := range r.Raw {
|
||||
// Add trailing line
|
||||
raw += "\n"
|
||||
|
||||
// Build a parsed request from raw
|
||||
parsedReq, err := http.ReadRequest(bufio.NewReader(strings.NewReader(raw)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(r.Payloads) > 0 {
|
||||
basePayloads := generators.LoadWordlists(r.Payloads)
|
||||
generatorFunc := generators.SniperGenerator
|
||||
switch r.attackType {
|
||||
case generators.PitchFork:
|
||||
generatorFunc = generators.PitchforkGenerator
|
||||
case generators.ClusterBomb:
|
||||
generatorFunc = generators.ClusterbombGenerator
|
||||
}
|
||||
|
||||
for genValues := range generatorFunc(basePayloads) {
|
||||
baseValues := generators.CopyMap(values)
|
||||
finValues := generators.MergeMaps(baseValues, genValues)
|
||||
|
||||
replacer := newReplacer(finValues)
|
||||
|
||||
// Replace the dynamic variables in the URL if any
|
||||
raw := replacer.Replace(raw)
|
||||
|
||||
dynamicValues := make(map[string]interface{})
|
||||
// find all potentials tokens between {{}}
|
||||
var re = regexp.MustCompile(`(?m)\{\{.+}}`)
|
||||
for _, match := range re.FindAllString(raw, -1) {
|
||||
// check if the match contains a dynamic variable
|
||||
if generators.StringContainsAnyMapItem(finValues, match) {
|
||||
expr := generators.TrimDelimiters(match)
|
||||
compiled, err := govaluate.NewEvaluableExpressionWithFunctions(expr, generators.HelperFunctions())
|
||||
if err != nil {
|
||||
// Debug only - Remove
|
||||
log.Fatal(err)
|
||||
}
|
||||
result, err := compiled.Evaluate(finValues)
|
||||
if err != nil {
|
||||
// Debug only - Remove
|
||||
log.Fatal(err)
|
||||
}
|
||||
dynamicValues[expr] = result
|
||||
}
|
||||
}
|
||||
|
||||
// replace dynamic values
|
||||
dynamicReplacer := newReplacer(dynamicValues)
|
||||
raw = dynamicReplacer.Replace(raw)
|
||||
|
||||
// log.Println(raw)
|
||||
|
||||
// Build a parsed request from raw
|
||||
parsedReq, err := http.ReadRequest(bufio.NewReader(strings.NewReader(raw)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// requests generated from http.ReadRequest have incorrect RequestURI, so they
|
||||
// cannot be used to perform another request directly, we need to generate a new one
|
||||
// with the new target url
|
||||
finalURL := fmt.Sprintf("%s%s", baseURL, parsedReq.URL)
|
||||
req, err := http.NewRequest(r.Method, finalURL, parsedReq.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// copy headers
|
||||
req.Header = parsedReq.Header.Clone()
|
||||
|
||||
request, err := r.fillRequest(req, values)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
requests <- request
|
||||
}
|
||||
} else {
|
||||
// otherwise continue with normal flow
|
||||
|
||||
// base request
|
||||
replacer := newReplacer(values)
|
||||
// Replace the dynamic variables in the request if any
|
||||
raw = replacer.Replace(raw)
|
||||
|
||||
// Build a parsed request from raw
|
||||
parsedReq, err := http.ReadRequest(bufio.NewReader(strings.NewReader(raw)))
|
||||
if err != nil {
|
||||
// find a way to pass the error
|
||||
return
|
||||
}
|
||||
|
||||
// requests generated from http.ReadRequest have incorrect RequestURI, so they
|
||||
// cannot be used to perform another request directly, we need to generate a new one
|
||||
// with the new target url
|
||||
finalURL := fmt.Sprintf("%s%s", baseURL, parsedReq.URL)
|
||||
req, err := http.NewRequest(r.Method, finalURL, parsedReq.Body)
|
||||
if err != nil {
|
||||
// find a way to pass the error
|
||||
return
|
||||
}
|
||||
|
||||
// copy headers
|
||||
req.Header = parsedReq.Header.Clone()
|
||||
|
||||
request, err := r.fillRequest(req, values)
|
||||
if err != nil {
|
||||
// find a way to pass the error
|
||||
return
|
||||
}
|
||||
|
||||
requests <- request
|
||||
}
|
||||
}
|
||||
|
||||
// requests generated from http.ReadRequest have incorrect RequestURI, so they
|
||||
// cannot be used to perform another request directly, we need to generate a new one
|
||||
// with the new target url
|
||||
finalURL := fmt.Sprintf("%s%s", baseURL, parsedReq.URL)
|
||||
req, err := http.NewRequest(r.Method, finalURL, parsedReq.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// copy headers
|
||||
req.Header = parsedReq.Header.Clone()
|
||||
|
||||
request, err := r.fillRequest(req, values)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
requests = append(requests, request)
|
||||
}
|
||||
}()
|
||||
|
||||
return requests, nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package templates
|
|||
import (
|
||||
"os"
|
||||
|
||||
"github.com/projectdiscovery/nuclei/pkg/generators"
|
||||
"github.com/projectdiscovery/nuclei/pkg/matchers"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
@ -33,6 +34,13 @@ func ParseTemplate(file string) (*Template, error) {
|
|||
request.SetMatchersCondition(condition)
|
||||
}
|
||||
|
||||
attack, ok := generators.AttackTypes[request.AttackType]
|
||||
if !ok {
|
||||
request.SetAttackType(generators.Sniper)
|
||||
} else {
|
||||
request.SetAttackType(attack)
|
||||
}
|
||||
|
||||
for _, matcher := range request.Matchers {
|
||||
if err = matcher.CompileMatchers(); err != nil {
|
||||
return nil, err
|
||||
|
|
Loading…
Reference in New Issue