mirror of https://github.com/daffainfo/nuclei.git
Added matchers package
commit
69983ae4a2
|
@ -0,0 +1,48 @@
|
|||
package matchers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// CompileMatchers performs the initial setup operation on a matcher
|
||||
func (m *Matcher) CompileMatchers() error {
|
||||
var ok bool
|
||||
|
||||
// Setup the matcher type
|
||||
m.matcherType, ok = MatcherTypes[m.Type]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown matcher type specified: %s", m.Type)
|
||||
}
|
||||
|
||||
// Compile the regexes
|
||||
for _, regex := range m.Regex {
|
||||
compiled, err := regexp.Compile(regex)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not compile regex: %s", regex)
|
||||
}
|
||||
|
||||
m.regexCompiled = append(m.regexCompiled, compiled)
|
||||
}
|
||||
|
||||
// Setup the condition type, if any.
|
||||
if m.Condition != "" {
|
||||
m.condition, ok = ConditionTypes[m.Condition]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown condition specified: %s", m.Condition)
|
||||
}
|
||||
} else {
|
||||
m.condition = ORCondition
|
||||
}
|
||||
|
||||
// Setup the part of the request to match, if any.
|
||||
if m.Part != "" {
|
||||
m.part, ok = PartTypes[m.Part]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown matcher part specified: %s", m.Part)
|
||||
}
|
||||
} else {
|
||||
m.part = BodyPart
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
package matchers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Match matches a http response again a given matcher
|
||||
func (m *Matcher) Match(resp *http.Response, body, headers string) bool {
|
||||
switch m.matcherType {
|
||||
case StatusMatcher:
|
||||
return m.matchStatusCode(resp.StatusCode)
|
||||
case SizeMatcher:
|
||||
return m.matchSizeCode(len(body))
|
||||
case WordsMatcher:
|
||||
// Match the parts as required for word check
|
||||
if m.part == BodyPart {
|
||||
return m.matchWords(body)
|
||||
} else if m.part == HeaderPart {
|
||||
return m.matchWords(headers)
|
||||
} else {
|
||||
if !m.matchWords(headers) {
|
||||
return false
|
||||
}
|
||||
return m.matchWords(body)
|
||||
}
|
||||
case RegexMatcher:
|
||||
// Match the parts as required for regex check
|
||||
if m.part == BodyPart {
|
||||
return m.matchRegex(body)
|
||||
} else if m.part == HeaderPart {
|
||||
return m.matchRegex(headers)
|
||||
} else {
|
||||
if !m.matchRegex(headers) {
|
||||
return false
|
||||
}
|
||||
return m.matchRegex(body)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// matchStatusCode matches a status code check against an HTTP Response
|
||||
func (m *Matcher) matchStatusCode(statusCode int) bool {
|
||||
// Iterate over all the status codes accepted as valid
|
||||
for _, status := range m.Status {
|
||||
// Continue if the status codes don't match
|
||||
if statusCode != status {
|
||||
// If we are in an AND request and a match failed,
|
||||
// return false as the AND condition fails on any single mismatch.
|
||||
if m.condition == ANDCondition {
|
||||
return false
|
||||
}
|
||||
// Continue with the flow since its an OR Condition.
|
||||
continue
|
||||
}
|
||||
|
||||
// If the condition was an OR, return on the first match.
|
||||
if m.condition == ORCondition {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// matchStatusCode matches a size check against an HTTP Response
|
||||
func (m *Matcher) matchSizeCode(length int) bool {
|
||||
// Iterate over all the sizes accepted as valid
|
||||
for _, size := range m.Size {
|
||||
// Continue if the size doesn't match
|
||||
if length != size {
|
||||
// If we are in an AND request and a match failed,
|
||||
// return false as the AND condition fails on any single mismatch.
|
||||
if m.condition == ANDCondition {
|
||||
return false
|
||||
}
|
||||
// Continue with the flow since its an OR Condition.
|
||||
continue
|
||||
}
|
||||
|
||||
// If the condition was an OR, return on the first match.
|
||||
if m.condition == ORCondition {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// matchWords matches a word check against an HTTP Response/Headers.
|
||||
func (m *Matcher) matchWords(corpus string) bool {
|
||||
// Iterate over all the words accepted as valid
|
||||
for _, word := range m.Words {
|
||||
// Continue if the word doesn't match
|
||||
if !strings.Contains(corpus, word) {
|
||||
// If we are in an AND request and a match failed,
|
||||
// return false as the AND condition fails on any single mismatch.
|
||||
if m.condition == ANDCondition {
|
||||
return false
|
||||
}
|
||||
// Continue with the flow since its an OR Condition.
|
||||
continue
|
||||
}
|
||||
|
||||
// If the condition was an OR, return on the first match.
|
||||
if m.condition == ORCondition {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// matchRegex matches a regex check against an HTTP Response/Headers.
|
||||
func (m *Matcher) matchRegex(corpus string) bool {
|
||||
// Iterate over all the regexes accepted as valid
|
||||
for _, regex := range m.regexCompiled {
|
||||
// Continue if the regex doesn't match
|
||||
if !regex.MatchString(corpus) {
|
||||
// If we are in an AND request and a match failed,
|
||||
// return false as the AND condition fails on any single mismatch.
|
||||
if m.condition == ANDCondition {
|
||||
return false
|
||||
}
|
||||
// Continue with the flow since its an OR Condition.
|
||||
continue
|
||||
}
|
||||
|
||||
// If the condition was an OR, return on the first match.
|
||||
if m.condition == ORCondition {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package matchers
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// Matcher is used to identify whether a template was successful.
|
||||
type Matcher struct {
|
||||
// Type is the type of the matcher
|
||||
Type string `yaml:"type"`
|
||||
// matcherType is the internal type of the matcher
|
||||
matcherType MatcherType
|
||||
|
||||
// Status are the acceptable status codes for the response
|
||||
Status []int `yaml:"status,omitempty"`
|
||||
// Size is the acceptable size for the response
|
||||
Size []int `yaml:"size,omitempty"`
|
||||
// Words are the words required to be present in the response
|
||||
Words []string `yaml:"words,omitempty"`
|
||||
// Regex are the regex pattern required to be present in the response
|
||||
Regex []string `yaml:"regex,omitempty"`
|
||||
// regexCompiled is the compiled variant
|
||||
regexCompiled []*regexp.Regexp
|
||||
|
||||
// Condition is the optional condition between two matcher variables
|
||||
//
|
||||
// By default, the condition is assumed to be OR.
|
||||
Condition string `yaml:"condition,omitempty"`
|
||||
// condition is the condition of the matcher
|
||||
condition ConditionType
|
||||
|
||||
// Part is the part of the request to match
|
||||
//
|
||||
// By default, matching is performed in request body.
|
||||
Part string `yaml:"part,omitempty"`
|
||||
// part is the part of the request to match
|
||||
part Part
|
||||
}
|
||||
|
||||
// MatcherType is the type of the matcher specified
|
||||
type MatcherType = int
|
||||
|
||||
const (
|
||||
// WordsMatcher matches responses with words
|
||||
WordsMatcher MatcherType = iota + 1
|
||||
// RegexMatcher matches responses with regexes
|
||||
RegexMatcher
|
||||
// StatusMatcher matches responses with status codes
|
||||
StatusMatcher
|
||||
// SizeMatcher matches responses with response size
|
||||
SizeMatcher
|
||||
)
|
||||
|
||||
// MatcherTypes is an table for conversion of matcher type from string.
|
||||
var MatcherTypes = map[string]MatcherType{
|
||||
"status": StatusMatcher,
|
||||
"size": SizeMatcher,
|
||||
"word": WordsMatcher,
|
||||
"regex": RegexMatcher,
|
||||
}
|
||||
|
||||
// ConditionType is the type of condition for matcher
|
||||
type ConditionType int
|
||||
|
||||
const (
|
||||
// ANDCondition matches responses with AND condition in arguments.
|
||||
ANDCondition ConditionType = iota + 1
|
||||
// ORCondition matches responses with AND condition in arguments.
|
||||
ORCondition
|
||||
)
|
||||
|
||||
// ConditionTypes is an table for conversion of condition type from string.
|
||||
var ConditionTypes = map[string]ConditionType{
|
||||
"and": ANDCondition,
|
||||
"or": ORCondition,
|
||||
}
|
||||
|
||||
// Part is the part of the request to match
|
||||
type Part int
|
||||
|
||||
const (
|
||||
// BodyPart matches body of the response.
|
||||
BodyPart Part = iota + 1
|
||||
// HeaderPart matches headers of the response.
|
||||
HeaderPart
|
||||
// AllPart matches both response body and headers of the response.
|
||||
AllPart
|
||||
)
|
||||
|
||||
// PartTypes is an table for conversion of part type from string.
|
||||
var PartTypes = map[string]Part{
|
||||
"body": BodyPart,
|
||||
"header": HeaderPart,
|
||||
"all": AllPart,
|
||||
}
|
Loading…
Reference in New Issue