mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
fix: 非标准端口的服务无法匹配对应插件 #588
端口扫描识别到 8881 上运行 SSH,但 SSH 插件只注册了 [22,2222,2200,22222], 端口不匹配导致插件不执行。 新增服务名称缓存:端口扫描阶段记录 host:port → serviceName, 插件匹配时端口不命中则回退到服务名称匹配。
This commit is contained in:
@@ -115,6 +115,7 @@ func (b *BaseScanStrategy) isLocalPluginExplicitlySpecified(pluginName string, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
// isPluginApplicableToPortWithHost 检查插件是否适用于指定端口
|
// isPluginApplicableToPortWithHost 检查插件是否适用于指定端口
|
||||||
|
// 匹配策略:端口匹配 → 服务名称匹配(解决非标准端口问题)
|
||||||
func (b *BaseScanStrategy) isPluginApplicableToPortWithHost(pluginName string, targetHost string, targetPort int) bool {
|
func (b *BaseScanStrategy) isPluginApplicableToPortWithHost(pluginName string, targetHost string, targetPort int) bool {
|
||||||
if b.isWebPlugin(pluginName) {
|
if b.isWebPlugin(pluginName) {
|
||||||
return IsMarkedWebService(targetHost, targetPort)
|
return IsMarkedWebService(targetHost, targetPort)
|
||||||
@@ -136,6 +137,16 @@ func (b *BaseScanStrategy) isPluginApplicableToPortWithHost(pluginName string, t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 端口不匹配时,按服务识别结果匹配
|
||||||
|
// 例:8881 端口上识别到 ssh 服务 → ssh 插件应该执行
|
||||||
|
if targetHost != "" && targetPort > 0 {
|
||||||
|
if svcName, ok := GetServiceName(targetHost, targetPort); ok {
|
||||||
|
if strings.EqualFold(svcName, pluginName) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-2
@@ -472,14 +472,21 @@ func buildWebServiceURL(addr string, serviceInfo *ServiceInfo) string {
|
|||||||
return fmt.Sprintf("%s://%s", protocol, addr)
|
return fmt.Sprintf("%s://%s", protocol, addr)
|
||||||
}
|
}
|
||||||
if protocol == "http" && port == "80" {
|
if protocol == "http" && port == "80" {
|
||||||
return fmt.Sprintf("http://%s", host)
|
return fmt.Sprintf("http://%s", urlHost(host))
|
||||||
}
|
}
|
||||||
if protocol == "https" && port == "443" {
|
if protocol == "https" && port == "443" {
|
||||||
return fmt.Sprintf("https://%s", host)
|
return fmt.Sprintf("https://%s", urlHost(host))
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(host, port))
|
return fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(host, port))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func urlHost(host string) string {
|
||||||
|
if strings.Contains(host, ":") && !strings.HasPrefix(host, "[") {
|
||||||
|
return "[" + host + "]"
|
||||||
|
}
|
||||||
|
return host
|
||||||
|
}
|
||||||
|
|
||||||
// scanSinglePort 扫描单个端口并进行服务识别(重构后的简洁版本)
|
// scanSinglePort 扫描单个端口并进行服务识别(重构后的简洁版本)
|
||||||
func scanSinglePort(ctx context.Context, host string, port int, addr string, adaptiveTO *AdaptiveTimeout, metrics *ScanMetrics, count *atomic.Int64, collector *resultCollector, failedCollector *failedPortCollector, session *common.ScanSession) {
|
func scanSinglePort(ctx context.Context, host string, port int, addr string, adaptiveTO *AdaptiveTimeout, metrics *ScanMetrics, count *atomic.Int64, collector *resultCollector, failedCollector *failedPortCollector, session *common.ScanSession) {
|
||||||
config := session.Config
|
config := session.Config
|
||||||
@@ -700,6 +707,9 @@ func processServiceResult(ctx context.Context, host string, port int, addr strin
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 缓存服务名称,供插件按服务类型匹配(解决非标准端口问题)
|
||||||
|
MarkServiceName(host, port, serviceInfo.Name)
|
||||||
|
|
||||||
// 保存并输出服务信息
|
// 保存并输出服务信息
|
||||||
details := buildServiceDetails(port, serviceInfo)
|
details := buildServiceDetails(port, serviceInfo)
|
||||||
isWeb := IsWebServiceByFingerprint(serviceInfo)
|
isWeb := IsWebServiceByFingerprint(serviceInfo)
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 服务识别缓存:host:port → 服务名称
|
||||||
|
// 端口扫描阶段写入,插件匹配阶段读取
|
||||||
|
// 解决非标准端口上的服务无法匹配对应插件的问题
|
||||||
|
var (
|
||||||
|
serviceNameCache = make(map[string]string)
|
||||||
|
serviceCacheMu sync.RWMutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarkServiceName 记录端口上识别到的服务名称
|
||||||
|
func MarkServiceName(host string, port int, serviceName string) {
|
||||||
|
if serviceName == "" || serviceName == "unknown" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
key := net.JoinHostPort(host, strconv.Itoa(port))
|
||||||
|
serviceCacheMu.Lock()
|
||||||
|
serviceNameCache[key] = strings.ToLower(serviceName)
|
||||||
|
serviceCacheMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetServiceName 查询端口上的服务名称
|
||||||
|
func GetServiceName(host string, port int) (string, bool) {
|
||||||
|
key := net.JoinHostPort(host, strconv.Itoa(port))
|
||||||
|
serviceCacheMu.RLock()
|
||||||
|
name, ok := serviceNameCache[key]
|
||||||
|
serviceCacheMu.RUnlock()
|
||||||
|
return name, ok
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user