Skip to content

Commit

Permalink
more additions + new parsedPattern features
Browse files Browse the repository at this point in the history
  • Loading branch information
Ice3man543 committed Jun 20, 2024
1 parent 71c54d7 commit 7fd83c3
Show file tree
Hide file tree
Showing 6 changed files with 424 additions and 114 deletions.
148 changes: 39 additions & 109 deletions fingerprints.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package wappalyzer

import (
"fmt"
"regexp"
"strconv"
"strings"
)

// Fingerprints contains a map of fingerprints for tech detection
Expand Down Expand Up @@ -51,30 +48,30 @@ type CompiledFingerprint struct {
// icon contains a Icon associated with the fingerprint
icon string
// cookies contains fingerprints for target cookies
cookies map[string]*VersionRegex
cookies map[string]*ParsedPattern
// js contains fingerprints for the js file
js map[string]*VersionRegex
js map[string]*ParsedPattern
// dom contains fingerprints for the target dom
dom map[string]map[string]*VersionRegex
dom map[string]map[string]*ParsedPattern
// headers contains fingerprints for target headers
headers map[string]*VersionRegex
headers map[string]*ParsedPattern
// html contains fingerprints for the target HTML
html []*VersionRegex
html []*ParsedPattern
// script contains fingerprints for scripts
script []*VersionRegex
script []*ParsedPattern
// scriptSrc contains fingerprints for script srcs
scriptSrc []*VersionRegex
scriptSrc []*ParsedPattern
// meta contains fingerprints for meta tags
meta map[string][]*VersionRegex
meta map[string][]*ParsedPattern
// cpe contains the cpe for a fingerpritn
cpe string
}

func (f *CompiledFingerprint) GetJSRules() map[string]*VersionRegex {
func (f *CompiledFingerprint) GetJSRules() map[string]*ParsedPattern {
return f.js
}

func (f *CompiledFingerprint) GetDOMRules() map[string]map[string]*VersionRegex {
func (f *CompiledFingerprint) GetDOMRules() map[string]map[string]*ParsedPattern {
return f.dom
}

Expand All @@ -92,73 +89,6 @@ type CatsInfo struct {
Cats []int
}

type VersionRegex struct {
regex *regexp.Regexp
skipRegex bool
group int
}

const (
versionPrefix = "version:\\"
confidencePrefix = "confidence:"
)

// newVersionRegex creates a new version matching regex
// TODO: handles simple group cases only as of now (no ternary)
func newVersionRegex(value string) (*VersionRegex, error) {
splitted := strings.Split(value, "\\;")
if len(splitted) == 0 {
return nil, nil
}

compiled, err := regexp.Compile(splitted[0])
if err != nil {
return nil, err
}
skipRegex := splitted[0] == ""
regex := &VersionRegex{regex: compiled, skipRegex: skipRegex}
if skipRegex {
return regex, nil
}
for _, part := range splitted {
if strings.HasPrefix(part, confidencePrefix) {
confidence := strings.TrimPrefix(part, confidencePrefix)
if parsed, err := strconv.Atoi(confidence); err == nil {
if parsed < 10 { // Only use high confidence regex
return nil, nil
}
}
}
if strings.HasPrefix(part, versionPrefix) {
group := strings.TrimPrefix(part, versionPrefix)
if parsed, err := strconv.Atoi(group); err == nil {
regex.group = parsed
}
}
}
return regex, nil
}

// MatchString returns true if a version regex matched.
// The found version is also returned if any.
func (v *VersionRegex) MatchString(value string) (bool, string) {
if v.skipRegex {
return true, ""
}
matches := v.regex.FindAllStringSubmatch(value, -1)
if len(matches) == 0 {
return false, ""
}

var version string
if v.group > 0 {
for _, match := range matches {
version = match[v.group]
}
}
return true, version
}

// part is the part of the fingerprint to match
type part int

Expand All @@ -180,24 +110,24 @@ func compileFingerprint(fingerprint *Fingerprint) *CompiledFingerprint {
description: fingerprint.Description,
website: fingerprint.Website,
icon: fingerprint.Icon,
dom: make(map[string]map[string]*VersionRegex),
cookies: make(map[string]*VersionRegex),
js: make(map[string]*VersionRegex),
headers: make(map[string]*VersionRegex),
html: make([]*VersionRegex, 0, len(fingerprint.HTML)),
script: make([]*VersionRegex, 0, len(fingerprint.Script)),
scriptSrc: make([]*VersionRegex, 0, len(fingerprint.ScriptSrc)),
meta: make(map[string][]*VersionRegex),
dom: make(map[string]map[string]*ParsedPattern),
cookies: make(map[string]*ParsedPattern),
js: make(map[string]*ParsedPattern),
headers: make(map[string]*ParsedPattern),
html: make([]*ParsedPattern, 0, len(fingerprint.HTML)),
script: make([]*ParsedPattern, 0, len(fingerprint.Script)),
scriptSrc: make([]*ParsedPattern, 0, len(fingerprint.ScriptSrc)),
meta: make(map[string][]*ParsedPattern),
cpe: fingerprint.CPE,
}

for dom, patterns := range fingerprint.Dom {
compiled.dom[dom] = make(map[string]*VersionRegex)
compiled.dom[dom] = make(map[string]*ParsedPattern)

for attr, value := range patterns {
switch attr {
case "exists", "text":
pattern, err := newVersionRegex(value.(string))
pattern, err := ParsePattern(value.(string))
if err != nil {
continue
}
Expand All @@ -207,9 +137,9 @@ func compileFingerprint(fingerprint *Fingerprint) *CompiledFingerprint {
if !ok {
continue
}
compiled.dom[dom] = make(map[string]*VersionRegex)
compiled.dom[dom] = make(map[string]*ParsedPattern)
for attrName, value := range attrMap {
pattern, err := newVersionRegex(value.(string))
pattern, err := ParsePattern(value.(string))
if err != nil {
continue
}
Expand All @@ -220,58 +150,58 @@ func compileFingerprint(fingerprint *Fingerprint) *CompiledFingerprint {
}

for header, pattern := range fingerprint.Cookies {
fingerprint, err := newVersionRegex(pattern)
fingerprint, err := ParsePattern(pattern)
if err != nil {
continue
}
compiled.cookies[header] = fingerprint
}

for k, pattern := range fingerprint.JS {
fingerprint, err := newVersionRegex(pattern)
fingerprint, err := ParsePattern(pattern)
if err != nil {
continue
}
compiled.js[k] = fingerprint
}

for header, pattern := range fingerprint.Headers {
fingerprint, err := newVersionRegex(pattern)
fingerprint, err := ParsePattern(pattern)
if err != nil {
continue
}
compiled.headers[header] = fingerprint
}

for _, pattern := range fingerprint.HTML {
fingerprint, err := newVersionRegex(pattern)
fingerprint, err := ParsePattern(pattern)
if err != nil {
continue
}
compiled.html = append(compiled.html, fingerprint)
}

for _, pattern := range fingerprint.Script {
fingerprint, err := newVersionRegex(pattern)
fingerprint, err := ParsePattern(pattern)
if err != nil {
continue
}
compiled.script = append(compiled.script, fingerprint)
}

for _, pattern := range fingerprint.ScriptSrc {
fingerprint, err := newVersionRegex(pattern)
fingerprint, err := ParsePattern(pattern)
if err != nil {
continue
}
compiled.scriptSrc = append(compiled.scriptSrc, fingerprint)
}

for meta, patterns := range fingerprint.Meta {
var compiledList []*VersionRegex
var compiledList []*ParsedPattern

for _, pattern := range patterns {
fingerprint, err := newVersionRegex(pattern)
fingerprint, err := ParsePattern(pattern)
if err != nil {
continue
}
Expand All @@ -293,21 +223,21 @@ func (f *CompiledFingerprints) matchString(data string, part part) []string {
switch part {
case jsPart:
for _, pattern := range fingerprint.js {
if valid, versionString := pattern.MatchString(data); valid {
if valid, versionString := pattern.Evaluate(data); valid {
matched = true
version = versionString
}
}
case scriptPart:
for _, pattern := range fingerprint.scriptSrc {
if valid, versionString := pattern.MatchString(data); valid {
if valid, versionString := pattern.Evaluate(data); valid {
matched = true
version = versionString
}
}
case htmlPart:
for _, pattern := range fingerprint.html {
if valid, versionString := pattern.MatchString(data); valid {
if valid, versionString := pattern.Evaluate(data); valid {
matched = true
version = versionString
}
Expand Down Expand Up @@ -347,7 +277,7 @@ func (f *CompiledFingerprints) matchKeyValueString(key, value string, part part)
continue
}

if valid, versionString := pattern.MatchString(value); valid {
if valid, versionString := pattern.Evaluate(value); valid {
matched = true
version = versionString
break
Expand All @@ -359,7 +289,7 @@ func (f *CompiledFingerprints) matchKeyValueString(key, value string, part part)
continue
}

if valid, versionString := pattern.MatchString(value); valid {
if valid, versionString := pattern.Evaluate(value); valid {
matched = true
version = versionString
break
Expand All @@ -372,7 +302,7 @@ func (f *CompiledFingerprints) matchKeyValueString(key, value string, part part)
}

for _, pattern := range patterns {
if valid, versionString := pattern.MatchString(value); valid {
if valid, versionString := pattern.Evaluate(value); valid {
matched = true
version = versionString
break
Expand Down Expand Up @@ -417,7 +347,7 @@ func (f *CompiledFingerprints) matchMapString(keyValue map[string]string, part p
if pattern == nil {
matched = true
}
if valid, versionString := pattern.MatchString(value); valid {
if valid, versionString := pattern.Evaluate(value); valid {
matched = true
version = versionString
break
Expand All @@ -430,7 +360,7 @@ func (f *CompiledFingerprints) matchMapString(keyValue map[string]string, part p
continue
}

if valid, versionString := pattern.MatchString(value); valid {
if valid, versionString := pattern.Evaluate(value); valid {
matched = true
version = versionString
break
Expand All @@ -444,7 +374,7 @@ func (f *CompiledFingerprints) matchMapString(keyValue map[string]string, part p
}

for _, pattern := range patterns {
if valid, versionString := pattern.MatchString(value); valid {
if valid, versionString := pattern.Evaluate(value); valid {
matched = true
version = versionString
break
Expand Down
8 changes: 8 additions & 0 deletions fingerprints_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ func init() {
})
}

func GetRawFingerprints() string {
return fingerprints
}

func GetCategoriesMapping() map[int]categoryItem {
return categoriesMapping
}

type categoryItem struct {
Name string `json:"name"`
Priority int `json:"priority"`
Expand Down
Loading

0 comments on commit 7fd83c3

Please sign in to comment.