nuclei/v2/pkg/matchers/match.go

236 lines
6.1 KiB
Go
Raw Normal View History

2020-04-04 00:16:27 +05:30
package matchers
import (
"encoding/hex"
2020-04-04 00:16:27 +05:30
"net/http"
"strings"
2020-09-30 01:05:55 +02:00
"time"
2020-04-22 22:45:02 +02:00
"github.com/miekg/dns"
2020-10-21 22:30:53 +02:00
"github.com/projectdiscovery/nuclei/v2/pkg/generators"
2020-04-04 00:16:27 +05:30
)
// Match matches a http response again a given matcher
2020-10-21 22:30:53 +02:00
func (m *Matcher) Match(resp *http.Response, body, headers string, duration time.Duration, data map[string]interface{}) bool {
2020-04-04 00:16:27 +05:30
switch m.matcherType {
case StatusMatcher:
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchStatusCode(resp.StatusCode))
2020-04-04 00:16:27 +05:30
case SizeMatcher:
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchSizeCode(len(body)))
2020-04-04 00:16:27 +05:30
case WordsMatcher:
// Match the parts as required for word check
if m.part == BodyPart {
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchWords(body))
2020-04-04 00:16:27 +05:30
} else if m.part == HeaderPart {
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchWords(headers))
2020-04-04 00:16:27 +05:30
} else {
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchWords(headers) || m.matchWords(body))
2020-04-04 00:16:27 +05:30
}
case RegexMatcher:
// Match the parts as required for regex check
if m.part == BodyPart {
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchRegex(body))
2020-04-04 00:16:27 +05:30
} else if m.part == HeaderPart {
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchRegex(headers))
2020-04-04 00:16:27 +05:30
} else {
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchRegex(headers) || m.matchRegex(body))
2020-04-04 00:16:27 +05:30
}
case BinaryMatcher:
// Match the parts as required for binary characters check
if m.part == BodyPart {
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchBinary(body))
} else if m.part == HeaderPart {
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchBinary(headers))
} else {
2020-08-23 22:55:11 +05:30
return m.isNegative(m.matchBinary(headers) || m.matchBinary(body))
}
2020-04-26 23:32:58 +02:00
case DSLMatcher:
// Match complex query
2020-10-23 10:41:49 +02:00
return m.isNegative(m.matchDSL(generators.MergeMaps(HTTPToMap(resp, body, headers, duration, ""), data)))
2020-04-04 00:16:27 +05:30
}
2020-04-04 00:16:27 +05:30
return false
}
// MatchDNS matches a dns response against a given matcher
2020-04-22 22:45:02 +02:00
func (m *Matcher) MatchDNS(msg *dns.Msg) bool {
switch m.matcherType {
// [WIP] add dns status code matcher
case SizeMatcher:
return m.matchSizeCode(msg.Len())
case WordsMatcher:
// Match for word check
return m.matchWords(msg.String())
case RegexMatcher:
// Match regex check
return m.matchRegex(msg.String())
case BinaryMatcher:
// Match binary characters check
return m.matchBinary(msg.String())
2020-04-26 23:32:58 +02:00
case DSLMatcher:
// Match complex query
2020-10-23 10:41:49 +02:00
return m.matchDSL(DNSToMap(msg, ""))
2020-04-22 22:45:02 +02:00
}
2020-04-22 22:45:02 +02:00
return false
}
2020-04-04 00:16:27 +05:30
// 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
2020-04-04 00:32:03 +05:30
//
// Status codes don't support AND conditions.
2020-04-04 00:16:27 +05:30
for _, status := range m.Status {
// Continue if the status codes don't match
if statusCode != status {
continue
}
2020-04-04 00:32:03 +05:30
// Return on the first match.
return true
2020-04-04 00:16:27 +05:30
}
2020-04-04 00:16:27 +05:30
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
2020-04-04 00:32:03 +05:30
//
// Sizes codes don't support AND conditions.
2020-04-04 00:16:27 +05:30
for _, size := range m.Size {
// Continue if the size doesn't match
if length != size {
continue
}
2020-04-04 00:32:03 +05:30
// Return on the first match.
return true
2020-04-04 00:16:27 +05:30
}
2020-04-04 00:16:27 +05:30
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
2020-04-04 00:32:03 +05:30
for i, word := range m.Words {
2020-04-04 00:16:27 +05:30
// Continue if the word doesn't match
if !strings.Contains(corpus, word) {
2020-04-04 00:16:27 +05:30
// 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
}
2020-04-04 00:32:03 +05:30
// If we are at the end of the words, return with true
if len(m.Words)-1 == i {
return true
}
2020-04-04 00:16:27 +05:30
}
2020-04-04 00:16:27 +05:30
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
2020-04-04 00:32:03 +05:30
for i, regex := range m.regexCompiled {
2020-04-04 00:16:27 +05:30
// 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
}
2020-04-04 00:32:03 +05:30
// If we are at the end of the regex, return with true
if len(m.regexCompiled)-1 == i {
return true
}
2020-04-04 00:16:27 +05:30
}
2020-04-04 00:16:27 +05:30
return false
}
// matchWords matches a word check against an HTTP Response/Headers.
func (m *Matcher) matchBinary(corpus string) bool {
// Iterate over all the words accepted as valid
for i, binary := range m.Binary {
// Continue if the word doesn't match
hexa, _ := hex.DecodeString(binary)
if !strings.Contains(corpus, string(hexa)) {
// 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
}
// If we are at the end of the words, return with true
if len(m.Binary)-1 == i {
return true
}
}
return false
}
2020-04-26 23:32:58 +02:00
// matchDSL matches on a generic map result
func (m *Matcher) matchDSL(mp map[string]interface{}) bool {
// Iterate over all the regexes accepted as valid
for i, expression := range m.dslCompiled {
result, err := expression.Evaluate(mp)
if err != nil {
continue
}
2020-04-26 23:32:58 +02:00
var bResult bool
bResult, ok := result.(bool)
// Continue if the regex doesn't match
if !ok || !bResult {
// 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
}
// If we are at the end of the dsl, return with true
if len(m.dslCompiled)-1 == i {
return true
}
}
2020-04-26 23:32:58 +02:00
return false
}