dddd/lib/gonmap/type-probe.go

181 lines
4.7 KiB
Go
Raw Normal View History

2023-08-18 08:55:46 +02:00
package gonmap
import (
"errors"
"fmt"
"github.com/lcvvvv/gonmap/simplenet"
"regexp"
"strconv"
"strings"
"time"
)
type probe struct {
//探针级别
rarity int
//探针名称
name string
//探针适用默认端口号
ports PortList
//探针适用SSL端口号
sslports PortList
//totalwaitms time.Duration
//tcpwrappedms time.Duration
//探针对应指纹库
matchGroup []*match
//探针指纹库若匹配失败则会尝试使用fallback指定探针的指纹库
fallback string
//探针发送协议类型
protocol string
//探针发送数据
sendRaw string
}
func (p *probe) scan(host string, port int, tls bool, timeout time.Duration, size int) (string, bool, error) {
uri := fmt.Sprintf("%s:%d", host, port)
sendRaw := strings.Replace(p.sendRaw, "{Host}", fmt.Sprintf("%s:%d", host, port), -1)
text, err := simplenet.Send(p.protocol, tls, uri, sendRaw, timeout, size)
if err == nil {
return text, tls, nil
}
if strings.Contains(err.Error(), "STEP1") && tls == true {
text, err := simplenet.Send(p.protocol, false, uri, p.sendRaw, timeout, size)
return text, false, err
}
return text, tls, err
}
func (p *probe) match(s string) *FingerPrint {
var f = &FingerPrint{}
var softFilter string
for _, m := range p.matchGroup {
//实现软筛选
if softFilter != "" {
if m.service != softFilter {
continue
}
}
//logger.Println("开始匹配正则:", m.service, m.patternRegexp.String())
if m.patternRegexp.MatchString(s) {
//标记当前正则
f.MatchRegexString = m.patternRegexp.String()
if m.soft {
//如果为软捕获,这设置筛选器
f.Service = m.service
softFilter = m.service
continue
} else {
//如果为硬捕获则直接获取指纹信息
m.makeVersionInfo(s, f)
f.Service = m.service
return f
}
}
}
return f
}
var probeExprRegx = regexp.MustCompile("^(UDP|TCP) ([a-zA-Z0-9-_./]+) (?:q\\|([^|]*)\\|)$")
var probeIntRegx = regexp.MustCompile(`^(\d+)$`)
var probeStrRegx = regexp.MustCompile(`^([a-zA-Z0-9-_./]+)$`)
func parseProbe(lines []string) *probe {
var p = &probe{}
p.ports = emptyPortList
p.sslports = emptyPortList
for _, line := range lines {
p.loadLine(line)
}
return p
}
func (p *probe) loadLine(s string) {
//分解命令
i := strings.Index(s, " ")
commandName := s[:i]
commandArgs := s[i+1:]
//逐行处理
switch commandName {
case "Probe":
p.loadProbe(commandArgs)
case "match":
p.loadMatch(commandArgs, false)
case "softmatch":
p.loadMatch(commandArgs, true)
case "ports":
p.loadPorts(commandArgs, false)
case "sslports":
p.loadPorts(commandArgs, true)
case "totalwaitms":
//p.totalwaitms = time.Duration(p.getInt(commandArgs)) * time.Millisecond
case "tcpwrappedms":
//p.tcpwrappedms = time.Duration(p.getInt(commandArgs)) * time.Millisecond
case "rarity":
p.rarity = p.getInt(commandArgs)
case "fallback":
p.fallback = p.getString(commandArgs)
}
}
func (p *probe) loadProbe(s string) {
//Probe <protocol> <probename> <probestring>
if !probeExprRegx.MatchString(s) {
panic(errors.New("probe 语句格式不正确"))
}
args := probeExprRegx.FindStringSubmatch(s)
if args[1] == "" || args[2] == "" {
panic(errors.New("probe 参数格式不正确"))
}
p.protocol = args[1]
p.name = args[1] + "_" + args[2]
str := args[3]
str = strings.ReplaceAll(str, `\0`, `\x00`)
str = strings.ReplaceAll(str, `"`, `${double-quoted}`)
str = `"` + str + `"`
str, _ = strconv.Unquote(str)
str = strings.ReplaceAll(str, `${double-quoted}`, `"`)
p.sendRaw = str
}
func (p *probe) loadMatch(s string, soft bool) {
//"match": misc.MakeRegexpCompile("^([a-zA-Z0-9-_./]+) m\\|([^|]+)\\|([is]{0,2}) (.*)$"),
//match <Service> <pattern>|<patternopt> [<versioninfo>]
// "matchVersioninfoProductname": misc.MakeRegexpCompile("p/([^/]+)/"),
// "matchVersioninfoVersion": misc.MakeRegexpCompile("v/([^/]+)/"),
// "matchVersioninfoInfo": misc.MakeRegexpCompile("i/([^/]+)/"),
// "matchVersioninfoHostname": misc.MakeRegexpCompile("h/([^/]+)/"),
// "matchVersioninfoOS": misc.MakeRegexpCompile("o/([^/]+)/"),
// "matchVersioninfoDevice": misc.MakeRegexpCompile("d/([^/]+)/"),
p.matchGroup = append(p.matchGroup, parseMatch(s, soft))
}
func (p *probe) loadPorts(expr string, ssl bool) {
if ssl {
p.sslports = parsePortList(expr)
} else {
p.ports = parsePortList(expr)
}
}
func (p *probe) getInt(expr string) int {
if !probeIntRegx.MatchString(expr) {
panic(errors.New("totalwaitms or tcpwrappedms 语句参数不正确"))
}
i, _ := strconv.Atoi(probeIntRegx.FindStringSubmatch(expr)[1])
return i
}
func (p *probe) getString(expr string) string {
if !probeStrRegx.MatchString(expr) {
panic(errors.New("fallback 语句参数不正确"))
}
return probeStrRegx.FindStringSubmatch(expr)[1]
}