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 }