208 lines
5.1 KiB
Go
Raw Normal View History

2020-06-26 10:23:54 +02:00
package workflows
import (
2020-07-10 09:04:38 +02:00
"sync"
tengo "github.com/d5/tengo/v2"
2020-06-29 17:43:08 +05:30
"github.com/projectdiscovery/gologger"
2020-07-04 23:00:11 +02:00
"github.com/projectdiscovery/nuclei/v2/internal/progress"
2020-07-25 20:11:46 +02:00
"github.com/projectdiscovery/nuclei/v2/pkg/atomicboolean"
2020-07-16 10:57:28 +02:00
"github.com/projectdiscovery/nuclei/v2/pkg/executer"
"github.com/projectdiscovery/nuclei/v2/pkg/generators"
2020-06-26 10:23:54 +02:00
)
2020-06-26 15:10:42 +02:00
// NucleiVar within the scripting engine
2020-06-26 10:23:54 +02:00
type NucleiVar struct {
tengo.ObjectImpl
2020-07-10 09:04:38 +02:00
Templates []*Template
URL string
InternalVars map[string]interface{}
sync.RWMutex
2020-06-29 17:43:08 +05:30
}
// Template contains HTTPOptions and DNSOptions for a single template
type Template struct {
2020-07-16 10:57:28 +02:00
HTTPOptions *executer.HTTPOptions
DNSOptions *executer.DNSOptions
Progress progress.IProgress
2020-06-26 10:23:54 +02:00
}
2020-06-26 15:10:42 +02:00
// TypeName of the variable
2020-06-26 10:23:54 +02:00
func (n *NucleiVar) TypeName() string {
return "nuclei-var"
}
2020-06-26 15:10:42 +02:00
// CanCall can be called from within the scripting engine
2020-06-26 10:23:54 +02:00
func (n *NucleiVar) CanCall() bool {
return true
}
// Call logic - args[0]=headers, args[1]=payloads
2020-06-26 10:23:54 +02:00
func (n *NucleiVar) Call(args ...tengo.Object) (ret tengo.Object, err error) {
2020-07-10 09:04:38 +02:00
n.InternalVars = make(map[string]interface{})
headers := make(map[string]string)
2020-07-13 03:30:07 +02:00
externalVars := make(map[string]interface{})
// if external variables are specified and matches the template ones, these gets overwritten
if len(args) >= 1 {
2020-07-16 16:15:24 +02:00
headers = iterableToMapString(args[0])
}
2020-06-26 10:23:54 +02:00
// if external variables are specified and matches the template ones, these gets overwritten
if len(args) >= 2 {
2020-07-16 16:15:24 +02:00
externalVars = iterableToMap(args[1])
}
2020-07-04 23:00:11 +02:00
2020-07-25 20:11:46 +02:00
var gotResult atomicboolean.AtomBool
2020-06-29 17:43:08 +05:30
for _, template := range n.Templates {
2020-07-27 00:00:06 +02:00
p := template.Progress
2020-06-29 17:43:08 +05:30
if template.HTTPOptions != nil {
p.AddToTotal(template.HTTPOptions.Template.GetHTTPRequestCount())
2020-07-18 21:42:23 +02:00
for _, request := range template.HTTPOptions.Template.BulkRequestsHTTP {
// apply externally supplied payloads if any
request.Headers = generators.MergeMapsWithStrings(request.Headers, headers)
// apply externally supplied payloads if any
2020-07-13 03:30:07 +02:00
request.Payloads = generators.MergeMaps(request.Payloads, externalVars)
2020-07-18 21:42:23 +02:00
template.HTTPOptions.BulkHttpRequest = request
2020-07-16 10:57:28 +02:00
httpExecuter, err := executer.NewHTTPExecuter(template.HTTPOptions)
2020-06-29 17:43:08 +05:30
if err != nil {
p.Drop(request.GetRequestCount())
2020-06-29 17:43:08 +05:30
gologger.Warningf("Could not compile request for template '%s': %s\n", template.HTTPOptions.Template.ID, err)
continue
}
2020-07-23 20:19:19 +02:00
result := httpExecuter.ExecuteHTTP(p, n.URL)
2020-07-10 09:04:38 +02:00
if result.Error != nil {
gologger.Warningf("Could not send request for template '%s': %s\n", template.HTTPOptions.Template.ID, result.Error)
2020-06-29 17:43:08 +05:30
continue
}
2020-07-10 09:04:38 +02:00
2020-07-25 20:11:46 +02:00
if result.GotResults {
gotResult.Or(result.GotResults)
2020-07-10 09:04:38 +02:00
n.addResults(&result)
2020-06-29 17:43:08 +05:30
}
}
2020-06-26 15:10:42 +02:00
}
2020-06-29 17:43:08 +05:30
if template.DNSOptions != nil {
p.AddToTotal(template.DNSOptions.Template.GetDNSRequestCount())
2020-06-29 17:43:08 +05:30
for _, request := range template.DNSOptions.Template.RequestsDNS {
template.DNSOptions.DNSRequest = request
2020-07-16 10:57:28 +02:00
dnsExecuter := executer.NewDNSExecuter(template.DNSOptions)
2020-07-27 00:00:06 +02:00
result := dnsExecuter.ExecuteDNS(p, n.URL)
2020-07-10 09:04:38 +02:00
if result.Error != nil {
gologger.Warningf("Could not compile request for template '%s': %s\n", template.HTTPOptions.Template.ID, result.Error)
2020-06-29 17:43:08 +05:30
continue
}
2020-07-10 09:04:38 +02:00
2020-07-25 20:11:46 +02:00
if result.GotResults {
gotResult.Or(result.GotResults)
2020-07-10 09:04:38 +02:00
n.addResults(&result)
2020-06-29 17:43:08 +05:30
}
}
2020-06-26 15:10:42 +02:00
}
}
2020-07-10 09:04:38 +02:00
2020-07-25 20:11:46 +02:00
if gotResult.Get() {
2020-06-29 17:43:08 +05:30
return tengo.TrueValue, nil
}
return tengo.FalseValue, nil
2020-06-26 10:23:54 +02:00
}
2020-07-10 09:04:38 +02:00
func (n *NucleiVar) IsFalsy() bool {
n.RLock()
defer n.RUnlock()
return len(n.InternalVars) == 0
}
2020-07-16 10:57:28 +02:00
func (n *NucleiVar) addResults(r *executer.Result) {
2020-07-10 09:04:38 +02:00
n.RLock()
defer n.RUnlock()
// add payload values as first, they will be accessible if not overwritter through
// payload_name (from template) => value
for k, v := range r.Meta {
n.InternalVars[k] = v
}
2020-07-26 22:07:03 +02:00
for k := range r.Matches {
n.InternalVars[k] = true
2020-07-10 09:04:38 +02:00
}
for k, v := range r.Extractions {
n.InternalVars[k] = v
}
}
// IndexGet returns the value for the given key.
func (n *NucleiVar) IndexGet(index tengo.Object) (res tengo.Object, err error) {
strIdx, ok := tengo.ToString(index)
if !ok {
err = tengo.ErrInvalidIndexType
return
}
r, ok := n.InternalVars[strIdx]
if !ok {
return tengo.UndefinedValue, nil
}
switch r.(type) {
2020-07-26 22:07:03 +02:00
case bool:
if r.(bool) {
res = tengo.TrueValue
} else {
res = tengo.FalseValue
}
case string:
res = &tengo.String{Value: r.(string)}
case []string:
rr, ok := r.([]string)
if !ok {
break
}
var resA []tengo.Object
for _, rrr := range rr {
resA = append(resA, &tengo.String{Value: rrr})
}
res = &tengo.Array{Value: resA}
2020-07-14 03:26:21 +02:00
}
2020-07-10 09:04:38 +02:00
return
}
2020-07-16 14:27:52 +02:00
func iterableToMap(t tengo.Object) map[string]interface{} {
m := make(map[string]interface{})
if t.CanIterate() {
i := t.Iterate()
for i.Next() {
key, ok := tengo.ToString(i.Key())
if !ok {
continue
}
value := tengo.ToInterface(i.Value())
m[key] = value
}
}
return m
}
2020-07-16 14:27:52 +02:00
func iterableToMapString(t tengo.Object) map[string]string {
m := make(map[string]string)
if t.CanIterate() {
i := t.Iterate()
for i.Next() {
key, ok := tengo.ToString(i.Key())
if !ok {
continue
}
if value, ok := tengo.ToString(i.Value()); ok {
m[key] = value
}
}
}
return m
}