adding support for dsl extractors

This commit is contained in:
Mzack9999 2022-04-20 11:32:13 +02:00
parent 3bbce299ae
commit 72c5c399ec
12 changed files with 68 additions and 7 deletions

View File

@ -5,7 +5,9 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/Knetic/govaluate"
"github.com/itchyny/gojq" "github.com/itchyny/gojq"
"github.com/projectdiscovery/nuclei/v2/pkg/operators/common/dsl"
) )
// CompileExtractors performs the initial setup operation on an extractor // CompileExtractors performs the initial setup operation on an extractor
@ -40,6 +42,14 @@ func (e *Extractor) CompileExtractors() error {
e.jsonCompiled = append(e.jsonCompiled, compiled) e.jsonCompiled = append(e.jsonCompiled, compiled)
} }
for _, dslExp := range e.DSL {
compiled, err := govaluate.NewEvaluableExpressionWithFunctions(dslExp, dsl.HelperFunctions())
if err != nil {
return fmt.Errorf("could not compile dsl: %s", dslExp)
}
e.dslCompiled = append(e.dslCompiled, compiled)
}
if e.CaseInsensitive { if e.CaseInsensitive {
if e.GetType() != KValExtractor { if e.GetType() != KValExtractor {
return fmt.Errorf("case-insensitive flag is supported only for 'kval' extractors (not '%s')", e.Type) return fmt.Errorf("case-insensitive flag is supported only for 'kval' extractors (not '%s')", e.Type)

View File

@ -2,6 +2,7 @@ package extractors
import ( import (
"encoding/json" "encoding/json"
"fmt"
"strings" "strings"
"github.com/antchfx/htmlquery" "github.com/antchfx/htmlquery"
@ -122,3 +123,24 @@ func (e *Extractor) ExtractJSON(corpus string) map[string]struct{} {
} }
return results return results
} }
// ExtractDSL execute the expression and returns the results
func (e *Extractor) ExtractDSL(data map[string]interface{}) map[string]struct{} {
results := make(map[string]struct{})
for _, compiledExpression := range e.dslCompiled {
result, err := compiledExpression.Evaluate(data)
if err != nil {
return results
}
if result != nil {
resultString := fmt.Sprint(result)
if resultString != "" {
results[resultString] = struct{}{}
}
}
}
return results
}

View File

@ -21,6 +21,8 @@ const (
XPathExtractor XPathExtractor
// name:json // name:json
JSONExtractor JSONExtractor
// name:dsl
DSLExtractor
limit limit
) )
@ -30,6 +32,7 @@ var extractorMappings = map[ExtractorType]string{
KValExtractor: "kval", KValExtractor: "kval",
XPathExtractor: "xpath", XPathExtractor: "xpath",
JSONExtractor: "json", JSONExtractor: "json",
DSLExtractor: "dsl",
} }
// GetType returns the type of the matcher // GetType returns the type of the matcher

View File

@ -3,6 +3,7 @@ package extractors
import ( import (
"regexp" "regexp"
"github.com/Knetic/govaluate"
"github.com/itchyny/gojq" "github.com/itchyny/gojq"
) )
@ -87,6 +88,11 @@ type Extractor struct {
// jsonCompiled is the compiled variant // jsonCompiled is the compiled variant
jsonCompiled []*gojq.Code jsonCompiled []*gojq.Code
// description: |
// Extracts using DSL expressions.
DSL []string
dslCompiled []*govaluate.EvaluableExpression
// description: | // description: |
// Part is the part of the request response to extract data from. // Part is the part of the request response to extract data from.
// //

View File

@ -0,0 +1,6 @@
package extractors
// SupportsMap determines if the extractor type requires a map
func SupportsMap(extractor *Extractor) bool {
return extractor.Type.ExtractorType == KValExtractor || extractor.Type.ExtractorType == DSLExtractor
}

View File

@ -48,7 +48,7 @@ func (request *Request) Match(data map[string]interface{}, matcher *matchers.Mat
// Extract performs extracting operation for an extractor on model and returns true or false. // Extract performs extracting operation for an extractor on model and returns true or false.
func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} { func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} {
item, ok := request.getMatchPart(extractor.Part, data) item, ok := request.getMatchPart(extractor.Part, data)
if !ok && extractor.Type.ExtractorType != extractors.KValExtractor { if !ok && !extractors.SupportsMap(extractor) {
return nil return nil
} }
@ -57,6 +57,8 @@ func (request *Request) Extract(data map[string]interface{}, extractor *extracto
return extractor.ExtractRegex(types.ToString(item)) return extractor.ExtractRegex(types.ToString(item))
case extractors.KValExtractor: case extractors.KValExtractor:
return extractor.ExtractKval(data) return extractor.ExtractKval(data)
case extractors.DSLExtractor:
return extractor.ExtractDSL(data)
} }
return nil return nil
} }

View File

@ -37,7 +37,7 @@ func (request *Request) Match(data map[string]interface{}, matcher *matchers.Mat
// Extract performs extracting operation for an extractor on model and returns true or false. // Extract performs extracting operation for an extractor on model and returns true or false.
func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} { func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} {
itemStr, ok := request.getMatchPart(extractor.Part, data) itemStr, ok := request.getMatchPart(extractor.Part, data)
if !ok && extractor.Type.ExtractorType != extractors.KValExtractor { if !ok && !extractors.SupportsMap(extractor) {
return nil return nil
} }
@ -46,6 +46,8 @@ func (request *Request) Extract(data map[string]interface{}, extractor *extracto
return extractor.ExtractRegex(itemStr) return extractor.ExtractRegex(itemStr)
case extractors.KValExtractor: case extractors.KValExtractor:
return extractor.ExtractKval(data) return extractor.ExtractKval(data)
case extractors.DSLExtractor:
return extractor.ExtractDSL(data)
} }
return nil return nil
} }

View File

@ -37,7 +37,7 @@ func (request *Request) Match(data map[string]interface{}, matcher *matchers.Mat
// Extract performs extracting operation for an extractor on model and returns true or false. // Extract performs extracting operation for an extractor on model and returns true or false.
func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} { func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} {
itemStr, ok := request.getMatchPart(extractor.Part, data) itemStr, ok := request.getMatchPart(extractor.Part, data)
if !ok && extractor.Type.ExtractorType != extractors.KValExtractor { if !ok && !extractors.SupportsMap(extractor) {
return nil return nil
} }
@ -46,6 +46,8 @@ func (request *Request) Extract(data map[string]interface{}, extractor *extracto
return extractor.ExtractRegex(itemStr) return extractor.ExtractRegex(itemStr)
case extractors.KValExtractor: case extractors.KValExtractor:
return extractor.ExtractKval(data) return extractor.ExtractKval(data)
case extractors.DSLExtractor:
return extractor.ExtractDSL(data)
} }
return nil return nil
} }

View File

@ -58,7 +58,7 @@ func getStatusCode(data map[string]interface{}) (int, bool) {
// Extract performs extracting operation for an extractor on model and returns true or false. // Extract performs extracting operation for an extractor on model and returns true or false.
func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} { func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} {
item, ok := request.getMatchPart(extractor.Part, data) item, ok := request.getMatchPart(extractor.Part, data)
if !ok && extractor.Type.ExtractorType != extractors.KValExtractor { if !ok && !extractors.SupportsMap(extractor) {
return nil return nil
} }
switch extractor.GetType() { switch extractor.GetType() {
@ -70,6 +70,8 @@ func (request *Request) Extract(data map[string]interface{}, extractor *extracto
return extractor.ExtractHTML(item) return extractor.ExtractHTML(item)
case extractors.JSONExtractor: case extractors.JSONExtractor:
return extractor.ExtractJSON(item) return extractor.ExtractJSON(item)
case extractors.DSLExtractor:
return extractor.ExtractDSL(data)
} }
return nil return nil
} }

View File

@ -37,7 +37,7 @@ func (request *Request) Match(data map[string]interface{}, matcher *matchers.Mat
// Extract performs extracting operation for an extractor on model and returns true or false. // Extract performs extracting operation for an extractor on model and returns true or false.
func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} { func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} {
itemStr, ok := request.getMatchPart(extractor.Part, data) itemStr, ok := request.getMatchPart(extractor.Part, data)
if !ok && extractor.Type.ExtractorType != extractors.KValExtractor { if !ok && !extractors.SupportsMap(extractor) {
return nil return nil
} }
@ -46,6 +46,8 @@ func (request *Request) Extract(data map[string]interface{}, extractor *extracto
return extractor.ExtractRegex(itemStr) return extractor.ExtractRegex(itemStr)
case extractors.KValExtractor: case extractors.KValExtractor:
return extractor.ExtractKval(data) return extractor.ExtractKval(data)
case extractors.DSLExtractor:
return extractor.ExtractDSL(data)
} }
return nil return nil
} }

View File

@ -58,7 +58,7 @@ func getStatusCode(data map[string]interface{}) (int, bool) {
// Extract performs extracting operation for an extractor on model and returns true or false. // Extract performs extracting operation for an extractor on model and returns true or false.
func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} { func (request *Request) Extract(data map[string]interface{}, extractor *extractors.Extractor) map[string]struct{} {
item, ok := getMatchPart(extractor.Part, data) item, ok := getMatchPart(extractor.Part, data)
if !ok && extractor.Type.ExtractorType != extractors.KValExtractor { if !ok && !extractors.SupportsMap(extractor) {
return nil return nil
} }
switch extractor.GetType() { switch extractor.GetType() {
@ -66,6 +66,8 @@ func (request *Request) Extract(data map[string]interface{}, extractor *extracto
return extractor.ExtractRegex(item) return extractor.ExtractRegex(item)
case extractors.KValExtractor: case extractors.KValExtractor:
return extractor.ExtractKval(data) return extractor.ExtractKval(data)
case extractors.DSLExtractor:
return extractor.ExtractDSL(data)
} }
return nil return nil
} }

View File

@ -144,7 +144,7 @@ func MakeDefaultExtractFunc(data map[string]interface{}, extractor *extractors.E
} }
item, ok := data[part] item, ok := data[part]
if !ok && extractor.Type.ExtractorType != extractors.KValExtractor { if !ok && !extractors.SupportsMap(extractor) {
return nil return nil
} }
itemStr := types.ToString(item) itemStr := types.ToString(item)
@ -158,6 +158,8 @@ func MakeDefaultExtractFunc(data map[string]interface{}, extractor *extractors.E
return extractor.ExtractJSON(itemStr) return extractor.ExtractJSON(itemStr)
case extractors.XPathExtractor: case extractors.XPathExtractor:
return extractor.ExtractHTML(itemStr) return extractor.ExtractHTML(itemStr)
case extractors.DSLExtractor:
return extractor.ExtractDSL(data)
} }
return nil return nil
} }