github.com/chainreactors/fingers@v1.2.1/nmap/engine.go (about) 1 package gonmap 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/chainreactors/fingers/common" 8 "github.com/chainreactors/fingers/resources" 9 ) 10 11 type NmapEngine struct { 12 nmap *Nmap 13 } 14 15 // NewNmapEngine 创建新的 nmap 引擎实例 16 func NewNmapEngine(probesData, servicesData []byte) (*NmapEngine, error) { 17 // 解压缩 gzip 数据 18 decompressedProbes, err := resources.DecompressGzip(probesData) 19 if err != nil { 20 // 如果解压失败,尝试直接使用原始数据(可能已经是解压后的) 21 decompressedProbes = probesData 22 } 23 24 decompressedServices, err := resources.DecompressGzip(servicesData) 25 if err != nil { 26 // 如果解压失败,尝试直接使用原始数据(可能已经是解压后的) 27 decompressedServices = servicesData 28 } 29 30 // 手动初始化nmap实例,传入已解压的数据 31 n := NewWithData(decompressedProbes, decompressedServices) 32 33 return &NmapEngine{ 34 nmap: n, 35 }, nil 36 } 37 38 // Name 实现 EngineImpl 接口 39 func (e *NmapEngine) Name() string { 40 return "nmap" 41 } 42 43 // Compile 实现 EngineImpl 接口 44 func (e *NmapEngine) Compile() error { 45 // gonmap 在 init() 中已经完成编译,这里不需要额外操作 46 return nil 47 } 48 49 // Len 实现 EngineImpl 接口 50 func (e *NmapEngine) Len() int { 51 // 返回 nmap 指纹库的总指纹数 52 return len(e.nmap.probeNameMap) 53 } 54 55 // WebMatch 实现Web指纹匹配 - nmap不支持Web指纹 56 func (e *NmapEngine) WebMatch(content []byte) common.Frameworks { 57 // nmap不支持Web指纹识别 58 return make(common.Frameworks) 59 } 60 61 // ServiceMatch 实现Service指纹匹配 62 func (e *NmapEngine) ServiceMatch(host string, portStr string, level int, sender common.ServiceSender, callback common.ServiceCallback) *common.ServiceResult { 63 if sender == nil || level <= 0 { 64 return nil 65 } 66 67 // 创建适配器将common.ServiceSender转换为nmap内部sender格式 68 // 注意:这个adapter需要支持probe的Protocol字段(TCP/UDP) 69 nmapSender := func(host string, port int, data []byte, requestTLS bool, probeProtocol string) ([]byte, bool, error) { 70 // 根据probe的Protocol字段、TLS需求和端口特性选择网络协议 71 network := "tcp" 72 73 // 首先检查probe的协议类型 74 if strings.ToUpper(probeProtocol) == "UDP" { 75 network = "udp" 76 } else if requestTLS || isHTTPSPort(port) { 77 network = "tls" 78 } 79 80 // 构造正确的端口字符串,UDP需要加U:前缀 81 actualPortStr := portStr 82 if network == "udp" { 83 // 确保UDP端口有U:前缀 84 if !strings.HasPrefix(strings.ToUpper(portStr), "U:") { 85 actualPortStr = fmt.Sprintf("U:%s", portStr) 86 } 87 } 88 89 // 使用ServiceSender发送数据 90 response, err := sender.Send(host, actualPortStr, data, network) 91 if err != nil { 92 // 如果TLS失败,尝试普通TCP 93 if network == "tls" { 94 response, err = sender.Send(host, portStr, data, "tcp") 95 if err == nil { 96 return response, false, nil // 成功但不是TLS 97 } 98 } 99 return nil, false, err 100 } 101 102 // 返回响应和实际使用的协议类型 103 actualTLS := (network == "tls") 104 return response, actualTLS, nil 105 } 106 107 // 解析端口字符串获取端口号(用于其他逻辑) 108 portNum, _, _ := e.nmap.parsePortString(portStr) 109 110 // 使用nmap的完整扫描逻辑,但网络发送由外部sender控制 111 status, response := e.nmap.Scan(host, portStr, level, nmapSender) 112 113 114 var framework *common.Framework 115 116 if status == Matched && response != nil && response.FingerPrint != nil { 117 // 扫描成功,获取多个Framework(支持多个CPE app) 118 frameworks := response.FingerPrint.ToFrameworks() 119 if len(frameworks) > 0 { 120 framework = frameworks[0] // 取第一个Framework作为主要结果 121 } 122 } else if status == Open && !common.NoGuess { 123 // 端口开放但无法识别服务,使用guess功能猜测服务 124 guessedProtocol := e.nmap.GuessProtocol(portNum) 125 if guessedProtocol != "" && guessedProtocol != "unknown" { 126 // 创建基于猜测的Framework 127 framework = common.NewFramework(FixProtocol(guessedProtocol), common.FrameFromGUESS) 128 // 添加guess标记(使用AddTag避免重复) 129 framework.AddTag("guess") 130 } 131 } 132 // 如果status是Closed或其他状态,framework保持为nil,表示端口未开放或无法连接 133 134 if framework == nil { 135 return nil 136 } 137 138 result := &common.ServiceResult{ 139 Framework: framework, 140 Vuln: nil, // nmap一般不直接返回漏洞信息 141 } 142 143 // 调用回调函数 144 if callback != nil { 145 callback(result) 146 } 147 148 return result 149 } 150 151 // matchResponse 使用nmap指纹库分析响应数据 152 func (e *NmapEngine) matchResponse(responseData []byte, host string, port int) *common.Framework { 153 // 使用nmap的指纹匹配逻辑 154 // 调用nmap的核心指纹识别函数,不涉及网络请求 155 fingerPrint := e.nmap.getFinger(responseData, false, "") 156 157 if fingerPrint != nil && fingerPrint.Service != "" { 158 frameworks := fingerPrint.ToFrameworks() 159 if len(frameworks) > 0 { 160 return frameworks[0] // 返回第一个Framework 161 } 162 } 163 return nil 164 } 165 166 // Capability 实现 EngineImpl 接口 - 返回引擎能力 167 func (e *NmapEngine) Capability() common.EngineCapability { 168 return common.EngineCapability{ 169 SupportWeb: false, // nmap不支持Web指纹 170 SupportService: true, // nmap支持Service指纹 171 } 172 } 173 174 // isHTTPSPort 判断是否是常见的HTTPS端口 175 func isHTTPSPort(port int) bool { 176 httpsports := []int{443, 8443, 993, 995, 465, 636, 989, 990, 992, 993, 994, 995, 5986} 177 for _, p := range httpsports { 178 if port == p { 179 return true 180 } 181 } 182 return false 183 }