mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00

主要改进: - 创建BaseScanStrategy基础类提取通用功能,减少60%代码重复 - 新增PortDiscoveryService分离端口发现逻辑,提升职责清晰度 - 优化插件匹配算法,从O(n×m×p)降至O(n×p)复杂度 - 修复插件适用性判断逻辑错误,确保精确端口匹配 - 完善国际化支持,新增21个i18n消息定义 - 代码行数显著减少:LocalScanner(-50%)、ServiceScanner(-42%)、WebScanner(-44%) 技术优化: - 组合模式替代继承,提升扩展性 - 策略模式实现插件过滤器,支持Local/Service/Web类型 - 服务分离提升可测试性和维护性 - 性能优化减少嵌套循环和重复计算 确保漏洞扫描插件列表与实际执行插件保持精确一致。
152 lines
4.0 KiB
Go
152 lines
4.0 KiB
Go
package core
|
|
|
|
import (
|
|
"github.com/shadow1ng/fscan/common"
|
|
"github.com/shadow1ng/fscan/common/i18n"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
// ServiceScanStrategy 服务扫描策略
|
|
type ServiceScanStrategy struct {
|
|
*BaseScanStrategy
|
|
portDiscovery *PortDiscoveryService
|
|
}
|
|
|
|
// NewServiceScanStrategy 创建新的服务扫描策略
|
|
func NewServiceScanStrategy() *ServiceScanStrategy {
|
|
return &ServiceScanStrategy{
|
|
BaseScanStrategy: NewBaseScanStrategy("服务扫描", FilterService),
|
|
portDiscovery: NewPortDiscoveryService(),
|
|
}
|
|
}
|
|
|
|
// Name 返回策略名称
|
|
func (s *ServiceScanStrategy) Name() string {
|
|
return i18n.GetText("scan_strategy_service_name")
|
|
}
|
|
|
|
// Description 返回策略描述
|
|
func (s *ServiceScanStrategy) Description() string {
|
|
return i18n.GetText("scan_strategy_service_desc")
|
|
}
|
|
|
|
// Execute 执行服务扫描策略
|
|
func (s *ServiceScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
|
// 验证扫描目标
|
|
if info.Host == "" {
|
|
common.LogError(i18n.GetText("parse_error_target_empty"))
|
|
return
|
|
}
|
|
|
|
// 输出扫描开始信息
|
|
s.LogScanStart()
|
|
|
|
// 验证插件配置
|
|
if err := s.ValidateConfiguration(); err != nil {
|
|
common.LogError(err.Error())
|
|
return
|
|
}
|
|
|
|
common.LogBase(i18n.GetText("scan_host_start"))
|
|
|
|
// 输出插件信息
|
|
s.LogPluginInfo()
|
|
|
|
// 执行主机扫描流程
|
|
s.performHostScan(info, ch, wg)
|
|
}
|
|
|
|
// performHostScan 执行主机扫描的完整流程
|
|
func (s *ServiceScanStrategy) performHostScan(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
|
// 使用端口发现服务发现目标
|
|
targetInfos, err := s.portDiscovery.DiscoverTargets(info.Host, info)
|
|
if err != nil {
|
|
common.LogError(err.Error())
|
|
return
|
|
}
|
|
|
|
// 执行漏洞扫描
|
|
if len(targetInfos) > 0 {
|
|
common.LogBase(i18n.GetText("scan_vulnerability_start"))
|
|
// 显示即将使用的漏洞扫描插件
|
|
s.LogVulnerabilityPluginInfo(targetInfos)
|
|
ExecuteScanTasks(targetInfos, s, ch, wg)
|
|
}
|
|
}
|
|
|
|
// PrepareTargets 准备目标信息
|
|
func (s *ServiceScanStrategy) PrepareTargets(info common.HostInfo) []common.HostInfo {
|
|
// 使用端口发现服务发现目标
|
|
targetInfos, err := s.portDiscovery.DiscoverTargets(info.Host, info)
|
|
if err != nil {
|
|
common.LogError(err.Error())
|
|
return nil
|
|
}
|
|
return targetInfos
|
|
}
|
|
|
|
// LogVulnerabilityPluginInfo 输出漏洞扫描插件信息
|
|
func (s *ServiceScanStrategy) LogVulnerabilityPluginInfo(targets []common.HostInfo) {
|
|
allPlugins, isCustomMode := s.GetPlugins()
|
|
|
|
// 收集所有目标端口用于插件适用性检查
|
|
portSet := make(map[int]bool)
|
|
for _, target := range targets {
|
|
if target.Ports != "" {
|
|
if port, err := strconv.Atoi(target.Ports); err == nil {
|
|
portSet[port] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取实际会被使用的插件列表(优化版本)
|
|
var vulnerabilityPlugins []string
|
|
for _, pluginName := range allPlugins {
|
|
plugin, exists := common.PluginManager[pluginName]
|
|
if !exists {
|
|
continue
|
|
}
|
|
|
|
// 检查插件是否对任何目标端口适用
|
|
if s.isPluginApplicableToAnyPort(plugin, portSet, isCustomMode) {
|
|
vulnerabilityPlugins = append(vulnerabilityPlugins, pluginName)
|
|
}
|
|
}
|
|
|
|
// 输出插件信息
|
|
if len(vulnerabilityPlugins) > 0 {
|
|
common.LogBase(i18n.GetText("scan_vulnerability_plugins", strings.Join(vulnerabilityPlugins, ", ")))
|
|
} else {
|
|
common.LogBase(i18n.GetText("scan_no_vulnerability_plugins"))
|
|
}
|
|
}
|
|
|
|
// isPluginApplicableToAnyPort 检查插件是否对任何端口适用(性能优化)
|
|
func (s *ServiceScanStrategy) isPluginApplicableToAnyPort(plugin common.ScanPlugin, portSet map[int]bool, isCustomMode bool) bool {
|
|
// 自定义模式下运行所有明确指定的插件
|
|
if isCustomMode {
|
|
return true
|
|
}
|
|
|
|
// 非自定义模式下,排除本地插件
|
|
if plugin.HasType(common.PluginTypeLocal) {
|
|
return false
|
|
}
|
|
|
|
// 无端口限制的插件适用于所有端口
|
|
if len(plugin.Ports) == 0 {
|
|
return true
|
|
}
|
|
|
|
// 有端口限制的插件:检查是否匹配任何目标端口
|
|
for port := range portSet {
|
|
if plugin.HasPort(port) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|