mirror of
https://github.com/SleepingBag945/dddd.git
synced 2025-06-08 22:16:43 +00:00
181 lines
4.7 KiB
Go
181 lines
4.7 KiB
Go
![]() |
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]
|
|||
|
}
|