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-16 10:57:28 +02:00
|
|
|
"github.com/projectdiscovery/nuclei/v2/pkg/executer"
|
2020-07-11 03:20:27 +02:00
|
|
|
"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
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-16 14:22:59 +02:00
|
|
|
// 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{})
|
2020-07-16 14:22:59 +02:00
|
|
|
headers := make(map[string]string)
|
2020-07-13 03:30:07 +02:00
|
|
|
externalVars := make(map[string]interface{})
|
2020-07-11 03:20:27 +02:00
|
|
|
|
|
|
|
|
// if external variables are specified and matches the template ones, these gets overwritten
|
2020-07-16 14:22:59 +02:00
|
|
|
if len(args) >= 1 {
|
|
|
|
|
headers = iterableToMapString(&args[0])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if external variables are specified and matches the template ones, these gets overwritten
|
|
|
|
|
if len(args) >= 2 {
|
|
|
|
|
externalVars = iterableToMap(&args[1])
|
2020-07-11 03:20:27 +02:00
|
|
|
}
|
|
|
|
|
|
2020-06-29 17:43:08 +05:30
|
|
|
var gotResult bool
|
|
|
|
|
for _, template := range n.Templates {
|
|
|
|
|
if template.HTTPOptions != nil {
|
|
|
|
|
for _, request := range template.HTTPOptions.Template.RequestsHTTP {
|
2020-07-16 14:22:59 +02:00
|
|
|
// 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-06-29 17:43:08 +05:30
|
|
|
template.HTTPOptions.HTTPRequest = 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 {
|
|
|
|
|
gologger.Warningf("Could not compile request for template '%s': %s\n", template.HTTPOptions.Template.ID, err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
2020-07-16 10:57:28 +02:00
|
|
|
result := httpExecuter.ExecuteHTTP(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-16 10:57:28 +02:00
|
|
|
if httpExecuter.GotResults() {
|
2020-06-29 17:43:08 +05:30
|
|
|
gotResult = true
|
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 {
|
|
|
|
|
for _, request := range template.DNSOptions.Template.RequestsDNS {
|
|
|
|
|
template.DNSOptions.DNSRequest = request
|
2020-07-16 10:57:28 +02:00
|
|
|
dnsExecuter := executer.NewDNSExecuter(template.DNSOptions)
|
|
|
|
|
result := dnsExecuter.ExecuteDNS(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-16 10:57:28 +02:00
|
|
|
if dnsExecuter.GotResults() {
|
2020-06-29 17:43:08 +05:30
|
|
|
gotResult = true
|
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-06-29 17:43:08 +05:30
|
|
|
if gotResult {
|
|
|
|
|
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()
|
|
|
|
|
|
2020-07-14 03:54:57 +02:00
|
|
|
// 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-10 09:04:38 +02:00
|
|
|
for k, v := range r.Matches {
|
|
|
|
|
n.InternalVars[k] = v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-14 03:54:57 +02:00
|
|
|
switch r.(type) {
|
|
|
|
|
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:22:59 +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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|