diff --git a/core/PortInfoSmart.go b/core/PortInfoSmart.go new file mode 100644 index 0000000..471b17a --- /dev/null +++ b/core/PortInfoSmart.go @@ -0,0 +1,182 @@ +package core + +import ( + "fmt" + "github.com/shadow1ng/fscan/common" + "net" + "time" +) + +// SmartPortInfoScanner 智能服务识别器:保持nmap准确性,优化网络交互 +type SmartPortInfoScanner struct { + Address string + Port int + Conn net.Conn + Timeout time.Duration + info *Info +} + +// NewSmartPortInfoScanner 创建智能服务识别器 +func NewSmartPortInfoScanner(addr string, port int, conn net.Conn, timeout time.Duration) *SmartPortInfoScanner { + return &SmartPortInfoScanner{ + Address: addr, + Port: port, + Conn: conn, + Timeout: timeout, + info: &Info{ + Address: addr, + Port: port, + Conn: conn, + Result: Result{ + Service: Service{}, + }, + }, + } +} + +// SmartIdentify 智能服务识别:Banner优先 + 优化的探测策略 +func (s *SmartPortInfoScanner) SmartIdentify() (*ServiceInfo, error) { + common.LogDebug(fmt.Sprintf("开始智能识别服务 %s:%d", s.Address, s.Port)) + + // 第一阶段:读取初始Banner(大部分服务会主动发送) + s.tryInitialBanner() + if s.info.Found { + return s.buildServiceInfo(), nil + } + + // 第二阶段:智能探测策略(减少探测器数量) + s.smartProbeStrategy() + + // 构造返回结果 + return s.buildServiceInfo(), nil +} + +// tryInitialBanner 尝试读取服务主动发送的Banner +func (s *SmartPortInfoScanner) tryInitialBanner() { + // 读取初始响应 + if response, err := s.info.Read(); err == nil && len(response) > 0 { + common.LogDebug(fmt.Sprintf("收到初始Banner: %d 字节", len(response))) + + // 使用原有的nmap指纹库解析Banner,保持准确性 + if s.info.tryProbes(response, []*Probe{null, commonProbe}) { + common.LogDebug("Banner识别成功") + return + } + } +} + +// smartProbeStrategy 智能探测策略:减少探测器数量但保持准确性 +func (s *SmartPortInfoScanner) smartProbeStrategy() { + // 记录已使用的探测器 + usedProbes := make(map[string]struct{}) + + // 优先使用端口专用的第一个探测器(而不是全部) + if s.tryFirstPortProbe(usedProbes) { + return + } + + // 如果端口专用探测失败,使用最有效的通用探测器 + s.tryBestGenericProbes(usedProbes) +} + +// tryFirstPortProbe 只尝试该端口的第一个专用探测器 +func (s *SmartPortInfoScanner) tryFirstPortProbe(usedProbes map[string]struct{}) bool { + // 检查是否有端口专用探测器 + portProbes := common.PortMap[s.info.Port] + if len(portProbes) == 0 { + return false + } + + // 只使用第一个(最可能的)探测器 + probeName := portProbes[0] + usedProbes[probeName] = struct{}{} + + probe := v.ProbesMapKName[probeName] + probeData, err := DecodeData(probe.Data) + if err != nil || len(probeData) == 0 { + return false + } + + common.LogDebug(fmt.Sprintf("使用首选探测器: %s", probeName)) + if response := s.info.Connect(probeData); len(response) > 0 { + // 使用当前探测器检查响应 + s.info.GetInfo(response, &probe) + if s.info.Found { + return true + } + + // 也用通用探测器检查这个响应 + if probeName != "NULL" { + return s.info.tryProbes(response, []*Probe{commonProbe}) + } + } + + return false +} + +// tryBestGenericProbes 使用最有效的通用探测器(限制数量) +func (s *SmartPortInfoScanner) tryBestGenericProbes(usedProbes map[string]struct{}) { + // 选择最有效的探测器:GetRequest适用于HTTP,GenericLines适用于大多数文本协议 + bestProbes := []string{"GetRequest", "GenericLines", "HTTPOptions"} + + for _, probeName := range bestProbes { + // 跳过已使用的探测器 + if _, used := usedProbes[probeName]; used { + continue + } + + probe, exists := v.ProbesMapKName[probeName] + if !exists { + continue + } + + probeData, err := DecodeData(probe.Data) + if err != nil || len(probeData) == 0 { + continue + } + + common.LogDebug(fmt.Sprintf("使用通用探测器: %s", probeName)) + response := s.info.Connect(probeData) + if len(response) == 0 { + continue + } + + // 检查当前探测器 + s.info.GetInfo(response, &probe) + if s.info.Found { + return + } + + // 也检查通用匹配 + if probeName != "GenericLines" { + if s.info.tryProbes(response, []*Probe{commonProbe}) { + return + } + } + } + + // 如果所有探测都失败,标记为未知服务 + if s.info.Result.Service.Name == "" { + s.info.Result.Service.Name = "unknown" + } +} + +// buildServiceInfo 构建ServiceInfo结果 +func (s *SmartPortInfoScanner) buildServiceInfo() *ServiceInfo { + result := &s.info.Result + + serviceInfo := &ServiceInfo{ + Name: result.Service.Name, + Banner: result.Banner, + Version: result.Service.Extras["version"], + Extras: make(map[string]string), + } + + // 复制额外信息 + for k, v := range result.Service.Extras { + serviceInfo.Extras[k] = v + } + + common.LogDebug(fmt.Sprintf("智能识别完成 %s:%d => %s", s.Address, s.Port, serviceInfo.Name)) + return serviceInfo +} \ No newline at end of file diff --git a/core/PortScan.go b/core/PortScan.go index 930d2e5..0bb29e8 100644 --- a/core/PortScan.go +++ b/core/PortScan.go @@ -92,8 +92,8 @@ func EnhancedPortScan(hosts []string, ports string, timeout int64) []string { Status: "open", Details: map[string]interface{}{"port": port}, }) - // 统一服务识别(默认启用,替代原有的-fp选项逻辑) - serviceInfo, err := NewPortInfoScanner(host, port, conn, to).Identify() + // 智能服务识别:保持准确性,优化网络交互 + serviceInfo, err := NewSmartPortInfoScanner(host, port, conn, to).SmartIdentify() if err == nil { // 构建结果详情 details := map[string]interface{}{"port": port, "service": serviceInfo.Name}