github.com/chainreactors/fingers@v1.2.1/nmap/type-match.go (about) 1 package gonmap 2 3 import ( 4 "errors" 5 "fmt" 6 "regexp" 7 "strconv" 8 "strings" 9 10 "github.com/chainreactors/fingers/common" 11 "github.com/dlclark/regexp2" 12 ) 13 14 type Match struct { 15 //match <Service> <pattern> <patternopt> [<versioninfo>] 16 Soft bool `json:"soft"` 17 Service string `json:"service"` 18 Pattern string `json:"pattern"` 19 PatternRegexp *regexp2.Regexp `json:"-"` // 不序列化正则对象 20 VersionInfo *FingerPrint `json:"version_info,omitempty"` 21 } 22 23 var matchLoadRegexps = []*regexp.Regexp{ 24 regexp.MustCompile("^([a-zA-Z0-9-_./]+) m\\|([^|]+)\\|([is]{0,2})(?: (.*))?$"), 25 regexp.MustCompile("^([a-zA-Z0-9-_./]+) m=([^=]+)=([is]{0,2})(?: (.*))?$"), 26 regexp.MustCompile("^([a-zA-Z0-9-_./]+) m%([^%]+)%([is]{0,2})(?: (.*))?$"), 27 regexp.MustCompile("^([a-zA-Z0-9-_./]+) m@([^@]+)@([is]{0,2})(?: (.*))?$"), 28 } 29 30 var matchVersionInfoRegexps = map[string]*regexp.Regexp{ 31 "PRODUCTNAME": regexp.MustCompile("p/([^/]+)/"), 32 "VERSION": regexp.MustCompile("v/([^/]+)/"), 33 "INFO": regexp.MustCompile("i/([^/]+)/"), 34 "HOSTNAME": regexp.MustCompile("h/([^/]+)/"), 35 "OS": regexp.MustCompile("o/([^/]+)/"), 36 "DEVICE": regexp.MustCompile("d/([^/]+)/"), 37 } 38 39 // CPE解析正则表达式,匹配 cpe:/ 格式的CPE条目 40 var matchCPERegexp = regexp.MustCompile(`cpe:/[^/\s]+/[^/\s]+/[^/\s\)]*(?:/[^/\s\)]*)*`) 41 42 var matchVersionInfoHelperRegxP = regexp.MustCompile(`\$P\((\d)\)`) 43 var matchVersionInfoHelperRegx = regexp.MustCompile(`\$(\d)`) 44 45 func parseMatch(s string, soft bool) *Match { 46 var m = &Match{} 47 var regx *regexp.Regexp 48 49 for _, r := range matchLoadRegexps { 50 if r.MatchString(s) { 51 regx = r 52 } 53 } 54 55 if regx == nil { 56 panic(errors.New("match 语句参数不正确")) 57 } 58 59 args := regx.FindStringSubmatch(s) 60 m.Soft = soft 61 m.Service = args[1] 62 m.Service = FixProtocol(m.Service) 63 m.Pattern = args[2] 64 m.PatternRegexp = m.getPatternRegexp(m.Pattern, args[3]) 65 m.VersionInfo = &FingerPrint{ 66 ProbeName: "", 67 MatchRegexString: "", 68 Service: m.Service, 69 ProductName: m.getVersionInfo(s, "PRODUCTNAME"), 70 Version: m.getVersionInfo(s, "VERSION"), 71 Info: m.getVersionInfo(s, "INFO"), 72 Hostname: m.getVersionInfo(s, "HOSTNAME"), 73 OperatingSystem: m.getVersionInfo(s, "OS"), 74 DeviceType: m.getVersionInfo(s, "DEVICE"), 75 CPEs: m.getCPEInfo(s), 76 CPEAttributes: m.getCPEAttributes(s), 77 } 78 return m 79 } 80 81 func (m *Match) getPatternRegexp(pattern string, opt string) *regexp2.Regexp { 82 pattern = strings.ReplaceAll(pattern, `\0`, `\x00`) 83 if opt != "" { 84 if strings.Contains(opt, "i") == false { 85 opt += "i" 86 } 87 if pattern[:1] == "^" { 88 pattern = fmt.Sprintf("^(?%s:%s", opt, pattern[1:]) 89 } else { 90 pattern = fmt.Sprintf("(?%s:%s", opt, pattern) 91 } 92 if pattern[len(pattern)-1:] == "$" { 93 pattern = fmt.Sprintf("%s)$", pattern[:len(pattern)-1]) 94 } else { 95 pattern = fmt.Sprintf("%s)", pattern) 96 } 97 } 98 //pattern = regexp.MustCompile(`\\x[89a-f][0-9a-f]`).ReplaceAllString(pattern,".") 99 regex, err := regexp2.Compile(pattern, regexp2.None) 100 if err != nil { 101 panic(err) 102 } 103 return regex 104 } 105 106 func (m *Match) getVersionInfo(s string, regID string) string { 107 if matchVersionInfoRegexps[regID].MatchString(s) { 108 return matchVersionInfoRegexps[regID].FindStringSubmatch(s)[1] 109 } else { 110 return "" 111 } 112 } 113 114 // getCPEInfo 提取match语句中的所有CPE条目 115 func (m *Match) getCPEInfo(s string) []string { 116 return matchCPERegexp.FindAllString(s, -1) 117 } 118 119 // getCPEAttributes 解析CPE条目为Attributes结构体 120 func (m *Match) getCPEAttributes(s string) []*common.Attributes { 121 cpeStrings := m.getCPEInfo(s) 122 var attributes []*common.Attributes 123 124 for _, cpeStr := range cpeStrings { 125 attr := common.NewAttributesWithCPE(cpeStr) 126 if attr != nil { 127 attributes = append(attributes, attr) 128 } 129 } 130 131 return attributes 132 } 133 134 func (m *Match) makeVersionInfo(s string, f *FingerPrint) { 135 f.Info = m.makeVersionInfoSubHelper(s, m.VersionInfo.Info) 136 f.DeviceType = m.makeVersionInfoSubHelper(s, m.VersionInfo.DeviceType) 137 f.Hostname = m.makeVersionInfoSubHelper(s, m.VersionInfo.Hostname) 138 f.OperatingSystem = m.makeVersionInfoSubHelper(s, m.VersionInfo.OperatingSystem) 139 f.ProductName = m.makeVersionInfoSubHelper(s, m.VersionInfo.ProductName) 140 f.Version = m.makeVersionInfoSubHelper(s, m.VersionInfo.Version) 141 f.Service = m.makeVersionInfoSubHelper(s, m.VersionInfo.Service) 142 143 // 处理CPE信息,支持变量替换 144 f.CPEs = m.makeVersionInfoCPEHelper(s, m.VersionInfo.CPEs) 145 f.CPEAttributes = m.makeVersionInfoCPEAttributesHelper(s, f.CPEs) 146 } 147 148 func (m *Match) makeVersionInfoSubHelper(s string, pattern string) string { 149 match, _ := m.PatternRegexp.FindStringMatch(s) 150 if match == nil { 151 return pattern 152 } 153 154 // 构建匹配组数组 155 var sArr []string 156 sArr = append(sArr, match.String()) // 完整匹配 157 for i := 1; i < match.GroupCount(); i++ { 158 group := match.GroupByNumber(i) 159 if group != nil { 160 sArr = append(sArr, group.String()) 161 } else { 162 sArr = append(sArr, "") 163 } 164 } 165 166 if len(sArr) == 1 { 167 return pattern 168 } 169 if pattern == "" { 170 return pattern 171 } 172 173 if matchVersionInfoHelperRegxP.MatchString(pattern) { 174 pattern = matchVersionInfoHelperRegxP.ReplaceAllStringFunc(pattern, func(repl string) string { 175 a := matchVersionInfoHelperRegxP.FindStringSubmatch(repl)[1] 176 return "$" + a 177 }) 178 } 179 180 if matchVersionInfoHelperRegx.MatchString(pattern) { 181 pattern = matchVersionInfoHelperRegx.ReplaceAllStringFunc(pattern, func(repl string) string { 182 i, _ := strconv.Atoi(matchVersionInfoHelperRegx.FindStringSubmatch(repl)[1]) 183 return sArr[i] 184 }) 185 } 186 pattern = strings.ReplaceAll(pattern, "\n", "") 187 pattern = strings.ReplaceAll(pattern, "\r", "") 188 return pattern 189 } 190 191 // makeVersionInfoCPEHelper 处理CPE列表,支持变量替换 192 func (m *Match) makeVersionInfoCPEHelper(s string, cpePatterns []string) []string { 193 var processedCPEs []string 194 195 for _, cpePattern := range cpePatterns { 196 processedCPE := m.makeVersionInfoSubHelper(s, cpePattern) 197 if processedCPE != "" { 198 processedCPEs = append(processedCPEs, processedCPE) 199 } 200 } 201 202 return processedCPEs 203 } 204 205 // makeVersionInfoCPEAttributesHelper 将处理后的CPE字符串转换为Attributes 206 func (m *Match) makeVersionInfoCPEAttributesHelper(s string, cpeStrings []string) []*common.Attributes { 207 var attributes []*common.Attributes 208 209 for _, cpeStr := range cpeStrings { 210 attr := common.NewAttributesWithCPE(cpeStr) 211 if attr != nil { 212 attributes = append(attributes, attr) 213 } 214 } 215 216 return attributes 217 }