github.com/chainreactors/fingers@v1.2.1/ehole/ehole.go (about)

     1  package ehole
     2  
     3  import (
     4  	"bytes"
     5  	"github.com/chainreactors/fingers/common"
     6  	"github.com/chainreactors/fingers/resources"
     7  	"github.com/chainreactors/utils/httputils"
     8  	"regexp"
     9  	"strings"
    10  )
    11  
    12  const (
    13  	KeywordMethod = "keyword"
    14  	RegularMethod = "regular"
    15  	FaviconMethod = "faviconhash"
    16  )
    17  
    18  const (
    19  	BodyLocation   = "body"
    20  	HeaderLocation = "header"
    21  	TitleLocation  = "title"
    22  )
    23  
    24  func NewEHoleEngine(data []byte) (*EHoleEngine, error) {
    25  	var engine *EHoleEngine
    26  	err := resources.UnmarshalData(data, &engine)
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  	err = engine.Compile()
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	return engine, nil
    35  }
    36  
    37  type EHoleEngine struct {
    38  	Fingerprints []*Fingerprint `json:"fingerprint"`
    39  	FaviconMap   map[string]string
    40  }
    41  
    42  func (engine *EHoleEngine) Name() string {
    43  	return "ehole"
    44  }
    45  
    46  func (engine *EHoleEngine) Len() int {
    47  	return len(engine.Fingerprints)
    48  }
    49  
    50  func (engine *EHoleEngine) Compile() error {
    51  	engine.FaviconMap = make(map[string]string)
    52  	for _, finger := range engine.Fingerprints {
    53  		if finger.Method == RegularMethod {
    54  			finger.compiledRegexp = make([]*regexp.Regexp, len(finger.Keyword))
    55  			for i, reg := range finger.Keyword {
    56  				/** Fix bug
    57  				 * 使用 append 会导致数组前面有 len(finger.Keyword) 个 nil,在 `reg.Match` 时导致 panic(144行)
    58  				 * 匹配引擎会将内容全部转小写,正则表达式也需要转小写
    59  				 */
    60  				//finger.compiledRegexp = append(finger.compiledRegexp, regexp.MustCompile(reg))
    61  				finger.compiledRegexp[i] = regexp.MustCompile(strings.ToLower(reg))
    62  			}
    63  		} else if finger.Method == KeywordMethod {
    64  			finger.LowerKeyword = make([]string, len(finger.Keyword))
    65  			for i, word := range finger.Keyword {
    66  				//finger.lowerKeyword = append(finger.lowerKeyword, strings.ToLower(word))
    67  				finger.LowerKeyword[i] = strings.ToLower(word)
    68  			}
    69  		} else if finger.Method == FaviconMethod {
    70  			for _, hash := range finger.Keyword {
    71  				engine.FaviconMap[hash] = finger.Cms
    72  			}
    73  		}
    74  	}
    75  	return nil
    76  }
    77  
    78  // WebMatch 实现Web指纹匹配
    79  func (engine *EHoleEngine) WebMatch(content []byte) common.Frameworks {
    80  	var header, body string
    81  	content = bytes.ToLower(content)
    82  	bodyBytes, headerBytes, ok := httputils.SplitHttpRaw(content)
    83  	if ok {
    84  		header = string(headerBytes)
    85  		body = string(bodyBytes)
    86  		return engine.MatchWithHeaderAndBody(header, body)
    87  	}
    88  	return make(common.Frameworks)
    89  }
    90  
    91  // ServiceMatch 实现Service指纹匹配 - ehole不支持Service指纹
    92  func (engine *EHoleEngine) ServiceMatch(host string, portStr string, level int, sender common.ServiceSender, callback common.ServiceCallback) *common.ServiceResult {
    93  	// ehole不支持Service指纹识别
    94  	return nil
    95  }
    96  
    97  func (engine *EHoleEngine) Capability() common.EngineCapability {
    98  	return common.EngineCapability{
    99  		SupportWeb:     true,  // ehole支持Web指纹
   100  		SupportService: false, // ehole不支持Service指纹
   101  	}
   102  }
   103  
   104  func (engine *EHoleEngine) MatchWithHeaderAndBody(header, body string) common.Frameworks {
   105  	frames := make(common.Frameworks)
   106  	for _, finger := range engine.Fingerprints {
   107  		frame := finger.Match(header, body)
   108  		if frame != nil {
   109  			frames.Add(frame)
   110  		}
   111  	}
   112  	return frames
   113  }
   114  
   115  type Fingerprint struct {
   116  	Cms            string   `json:"cms"`
   117  	Method         string   `json:"method"`
   118  	Location       string   `json:"location"`
   119  	Keyword        []string `json:"keyword"`
   120  	LowerKeyword   []string `json:"-"`
   121  	compiledRegexp []*regexp.Regexp
   122  }
   123  
   124  func (finger *Fingerprint) Match(header, body string) *common.Framework {
   125  	switch finger.Location {
   126  	case BodyLocation, TitleLocation:
   127  		if finger.MatchMethod(body) {
   128  			return common.NewFramework(finger.Cms, common.FrameFromEhole)
   129  		}
   130  	case HeaderLocation:
   131  		if finger.MatchMethod(header) {
   132  			return common.NewFramework(finger.Cms, common.FrameFromEhole)
   133  		}
   134  	default:
   135  		return nil
   136  	}
   137  	return nil
   138  }
   139  
   140  func (finger *Fingerprint) MatchMethod(content string) bool {
   141  	switch finger.Method {
   142  	case KeywordMethod:
   143  		return finger.MatchKeyword(content)
   144  	case RegularMethod:
   145  		return finger.MatchRegexp(content)
   146  	default:
   147  		return false
   148  	}
   149  }
   150  
   151  func (finger *Fingerprint) MatchKeyword(content string) bool {
   152  	// Fix bug: 匹配引擎会将内容全部转小写,这里需要使用 LowerKeyword 检测
   153  	//for _, k := range finger.Keyword {
   154  	for _, k := range finger.LowerKeyword {
   155  		if !strings.Contains(content, k) {
   156  			return false
   157  		}
   158  	}
   159  	return true
   160  }
   161  
   162  func (finger *Fingerprint) MatchRegexp(content string) bool {
   163  	for _, reg := range finger.compiledRegexp {
   164  		if !reg.Match([]byte(content)) {
   165  			return false
   166  		}
   167  	}
   168  	return true
   169  }