mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
refactor: 重构扫描器架构优化代码复用和性能
主要改进: - 创建BaseScanStrategy基础类提取通用功能,减少60%代码重复 - 新增PortDiscoveryService分离端口发现逻辑,提升职责清晰度 - 优化插件匹配算法,从O(n×m×p)降至O(n×p)复杂度 - 修复插件适用性判断逻辑错误,确保精确端口匹配 - 完善国际化支持,新增21个i18n消息定义 - 代码行数显著减少:LocalScanner(-50%)、ServiceScanner(-42%)、WebScanner(-44%) 技术优化: - 组合模式替代继承,提升扩展性 - 策略模式实现插件过滤器,支持Local/Service/Web类型 - 服务分离提升可测试性和维护性 - 性能优化减少嵌套循环和重复计算 确保漏洞扫描插件列表与实际执行插件保持精确一致。
This commit is contained in:
parent
e8a7c594e9
commit
6c93129cb1
@ -276,4 +276,8 @@ var ParseMessages = map[string]map[string]string{
|
|||||||
LangZH: "无效的扫描模式: %s",
|
LangZH: "无效的扫描模式: %s",
|
||||||
LangEN: "Invalid scan mode: %s",
|
LangEN: "Invalid scan mode: %s",
|
||||||
},
|
},
|
||||||
|
"parse_error_invalid_target_format": {
|
||||||
|
LangZH: "无效的目标地址格式: %s",
|
||||||
|
LangEN: "Invalid target address format: %s",
|
||||||
|
},
|
||||||
}
|
}
|
@ -73,6 +73,88 @@ var ScanMessages = map[string]map[string]string{
|
|||||||
LangEN: "Scan error %v:%v - %v",
|
LangEN: "Scan error %v:%v - %v",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ========================= 扫描器插件消息 =========================
|
||||||
|
"scan_local_start": {
|
||||||
|
LangZH: "开始本地信息收集",
|
||||||
|
LangEN: "Starting local information collection",
|
||||||
|
},
|
||||||
|
"scan_service_start": {
|
||||||
|
LangZH: "开始服务扫描",
|
||||||
|
LangEN: "Starting service scan",
|
||||||
|
},
|
||||||
|
"scan_web_start": {
|
||||||
|
LangZH: "开始Web扫描",
|
||||||
|
LangEN: "Starting web scan",
|
||||||
|
},
|
||||||
|
"scan_general_start": {
|
||||||
|
LangZH: "开始扫描",
|
||||||
|
LangEN: "Starting scan",
|
||||||
|
},
|
||||||
|
"scan_mode_local_prefix": {
|
||||||
|
LangZH: "本地模式",
|
||||||
|
LangEN: "Local mode",
|
||||||
|
},
|
||||||
|
"scan_mode_service_prefix": {
|
||||||
|
LangZH: "服务模式",
|
||||||
|
LangEN: "Service mode",
|
||||||
|
},
|
||||||
|
"scan_mode_web_prefix": {
|
||||||
|
LangZH: "Web模式",
|
||||||
|
LangEN: "Web mode",
|
||||||
|
},
|
||||||
|
"scan_plugins_local": {
|
||||||
|
LangZH: "使用本地插件: %s",
|
||||||
|
LangEN: "Using local plugins: %s",
|
||||||
|
},
|
||||||
|
"scan_plugins_service": {
|
||||||
|
LangZH: "使用服务插件: %s",
|
||||||
|
LangEN: "Using service plugins: %s",
|
||||||
|
},
|
||||||
|
"scan_plugins_web": {
|
||||||
|
LangZH: "使用Web插件: %s",
|
||||||
|
LangEN: "Using web plugins: %s",
|
||||||
|
},
|
||||||
|
"scan_plugins_custom_specified": {
|
||||||
|
LangZH: "使用指定插件: %s",
|
||||||
|
LangEN: "Using specified plugins: %s",
|
||||||
|
},
|
||||||
|
"scan_no_local_plugins": {
|
||||||
|
LangZH: "未找到可用的本地插件",
|
||||||
|
LangEN: "No available local plugins found",
|
||||||
|
},
|
||||||
|
"scan_no_web_plugins": {
|
||||||
|
LangZH: "未找到可用的Web插件",
|
||||||
|
LangEN: "No available web plugins found",
|
||||||
|
},
|
||||||
|
"scan_strategy_local_name": {
|
||||||
|
LangZH: "本地扫描",
|
||||||
|
LangEN: "Local Scan",
|
||||||
|
},
|
||||||
|
"scan_strategy_local_desc": {
|
||||||
|
LangZH: "收集本地系统信息",
|
||||||
|
LangEN: "Collect local system information",
|
||||||
|
},
|
||||||
|
"scan_strategy_service_name": {
|
||||||
|
LangZH: "服务扫描",
|
||||||
|
LangEN: "Service Scan",
|
||||||
|
},
|
||||||
|
"scan_strategy_service_desc": {
|
||||||
|
LangZH: "扫描主机服务和漏洞",
|
||||||
|
LangEN: "Scan host services and vulnerabilities",
|
||||||
|
},
|
||||||
|
"scan_strategy_web_name": {
|
||||||
|
LangZH: "Web扫描",
|
||||||
|
LangEN: "Web Scan",
|
||||||
|
},
|
||||||
|
"scan_strategy_web_desc": {
|
||||||
|
LangZH: "扫描Web应用漏洞和信息",
|
||||||
|
LangEN: "Scan web application vulnerabilities and information",
|
||||||
|
},
|
||||||
|
"scan_alive_hosts_count": {
|
||||||
|
LangZH: "存活主机数量: %d",
|
||||||
|
LangEN: "Alive hosts count: %d",
|
||||||
|
},
|
||||||
|
|
||||||
// ========================= 进度条消息 =========================
|
// ========================= 进度条消息 =========================
|
||||||
"progress_scanning_description": {
|
"progress_scanning_description": {
|
||||||
LangZH: "扫描进度",
|
LangZH: "扫描进度",
|
||||||
|
212
Core/BaseScanStrategy.go
Normal file
212
Core/BaseScanStrategy.go
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
BaseScanStrategy.go - 扫描策略基础类
|
||||||
|
|
||||||
|
提供所有扫描策略的通用功能,包括插件管理、验证、
|
||||||
|
日志输出等,减少代码重复并提升维护性。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// PluginFilterType 插件过滤类型
|
||||||
|
type PluginFilterType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FilterNone PluginFilterType = iota // 不过滤
|
||||||
|
FilterLocal // 仅本地插件
|
||||||
|
FilterService // 仅服务插件(排除本地)
|
||||||
|
FilterWeb // 仅Web插件
|
||||||
|
)
|
||||||
|
|
||||||
|
// BaseScanStrategy 扫描策略基础类
|
||||||
|
type BaseScanStrategy struct {
|
||||||
|
strategyName string
|
||||||
|
filterType PluginFilterType
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBaseScanStrategy 创建基础扫描策略
|
||||||
|
func NewBaseScanStrategy(name string, filterType PluginFilterType) *BaseScanStrategy {
|
||||||
|
return &BaseScanStrategy{
|
||||||
|
strategyName: name,
|
||||||
|
filterType: filterType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 插件管理通用方法
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// GetPlugins 获取插件列表(通用实现)
|
||||||
|
func (b *BaseScanStrategy) GetPlugins() ([]string, bool) {
|
||||||
|
// 如果指定了特定插件且不是"all"
|
||||||
|
if common.ScanMode != "" && common.ScanMode != "all" {
|
||||||
|
requestedPlugins := parsePluginList(common.ScanMode)
|
||||||
|
if len(requestedPlugins) == 0 {
|
||||||
|
requestedPlugins = []string{common.ScanMode}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证插件是否存在
|
||||||
|
var validPlugins []string
|
||||||
|
for _, name := range requestedPlugins {
|
||||||
|
if _, exists := common.PluginManager[name]; exists {
|
||||||
|
validPlugins = append(validPlugins, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return validPlugins, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未指定或使用"all":获取所有插件,由IsPluginApplicable做类型过滤
|
||||||
|
return GetAllPlugins(), false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetApplicablePlugins 获取适用的插件列表(用于日志显示)
|
||||||
|
func (b *BaseScanStrategy) GetApplicablePlugins(allPlugins []string, isCustomMode bool) []string {
|
||||||
|
if isCustomMode {
|
||||||
|
return allPlugins
|
||||||
|
}
|
||||||
|
|
||||||
|
var applicablePlugins []string
|
||||||
|
for _, pluginName := range allPlugins {
|
||||||
|
plugin, exists := common.PluginManager[pluginName]
|
||||||
|
if !exists {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.isPluginTypeMatched(plugin) {
|
||||||
|
applicablePlugins = append(applicablePlugins, pluginName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return applicablePlugins
|
||||||
|
}
|
||||||
|
|
||||||
|
// isPluginTypeMatched 检查插件类型是否匹配过滤器
|
||||||
|
func (b *BaseScanStrategy) isPluginTypeMatched(plugin common.ScanPlugin) bool {
|
||||||
|
switch b.filterType {
|
||||||
|
case FilterLocal:
|
||||||
|
return plugin.HasType(common.PluginTypeLocal)
|
||||||
|
case FilterService:
|
||||||
|
return !plugin.HasType(common.PluginTypeLocal)
|
||||||
|
case FilterWeb:
|
||||||
|
return plugin.HasType(common.PluginTypeWeb)
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPluginApplicable 判断插件是否适用(通用实现)
|
||||||
|
func (b *BaseScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
||||||
|
// 自定义模式下运行所有明确指定的插件
|
||||||
|
if isCustomMode {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查插件类型过滤
|
||||||
|
if !b.isPluginTypeMatched(plugin) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 对于服务扫描,还需检查端口匹配
|
||||||
|
if b.filterType == FilterService {
|
||||||
|
// 无端口限制的插件适用于所有端口
|
||||||
|
if len(plugin.Ports) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 有端口限制的插件:检查端口是否匹配
|
||||||
|
if targetPort > 0 {
|
||||||
|
return plugin.HasPort(targetPort)
|
||||||
|
}
|
||||||
|
// 如果没有提供目标端口,则不执行有端口限制的插件
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 日志输出通用方法
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// LogPluginInfo 输出插件信息(通用实现)
|
||||||
|
func (b *BaseScanStrategy) LogPluginInfo() {
|
||||||
|
allPlugins, isCustomMode := b.GetPlugins()
|
||||||
|
applicablePlugins := b.GetApplicablePlugins(allPlugins, isCustomMode)
|
||||||
|
|
||||||
|
// 生成日志消息
|
||||||
|
var messageKey, prefix string
|
||||||
|
switch b.filterType {
|
||||||
|
case FilterLocal:
|
||||||
|
messageKey = "scan_plugins_local"
|
||||||
|
prefix = i18n.GetText("scan_mode_local_prefix")
|
||||||
|
case FilterService:
|
||||||
|
messageKey = "scan_plugins_service"
|
||||||
|
prefix = i18n.GetText("scan_mode_service_prefix")
|
||||||
|
case FilterWeb:
|
||||||
|
messageKey = "scan_plugins_web"
|
||||||
|
prefix = i18n.GetText("scan_mode_web_prefix")
|
||||||
|
default:
|
||||||
|
messageKey = "scan_plugins_custom"
|
||||||
|
prefix = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(applicablePlugins) > 0 {
|
||||||
|
if isCustomMode {
|
||||||
|
common.LogBase(fmt.Sprintf("%s: %s", prefix,
|
||||||
|
i18n.GetText("scan_plugins_custom_specified", strings.Join(applicablePlugins, ", "))))
|
||||||
|
} else {
|
||||||
|
common.LogBase(fmt.Sprintf("%s: %s", prefix,
|
||||||
|
i18n.GetText(messageKey, strings.Join(applicablePlugins, ", "))))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
noPluginsKey := fmt.Sprintf("scan_no_%s_plugins", b.getFilterTypeName())
|
||||||
|
common.LogBase(fmt.Sprintf("%s: %s", prefix, i18n.GetText(noPluginsKey)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// getFilterTypeName 获取过滤器类型名称
|
||||||
|
func (b *BaseScanStrategy) getFilterTypeName() string {
|
||||||
|
switch b.filterType {
|
||||||
|
case FilterLocal:
|
||||||
|
return "local"
|
||||||
|
case FilterService:
|
||||||
|
return "service"
|
||||||
|
case FilterWeb:
|
||||||
|
return "web"
|
||||||
|
default:
|
||||||
|
return "general"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 验证通用方法
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// ValidateConfiguration 验证扫描配置(通用实现)
|
||||||
|
func (b *BaseScanStrategy) ValidateConfiguration() error {
|
||||||
|
return validateScanPlugins()
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// 通用辅助方法
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
// LogScanStart 输出扫描开始信息
|
||||||
|
func (b *BaseScanStrategy) LogScanStart() {
|
||||||
|
switch b.filterType {
|
||||||
|
case FilterLocal:
|
||||||
|
common.LogBase(i18n.GetText("scan_local_start"))
|
||||||
|
case FilterService:
|
||||||
|
common.LogBase(i18n.GetText("scan_service_start"))
|
||||||
|
case FilterWeb:
|
||||||
|
common.LogBase(i18n.GetText("scan_web_start"))
|
||||||
|
default:
|
||||||
|
common.LogBase(i18n.GetText("scan_general_start"))
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +1,40 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"strings"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalScanStrategy 本地扫描策略
|
// LocalScanStrategy 本地扫描策略
|
||||||
type LocalScanStrategy struct{}
|
type LocalScanStrategy struct {
|
||||||
|
*BaseScanStrategy
|
||||||
|
}
|
||||||
|
|
||||||
// NewLocalScanStrategy 创建新的本地扫描策略
|
// NewLocalScanStrategy 创建新的本地扫描策略
|
||||||
func NewLocalScanStrategy() *LocalScanStrategy {
|
func NewLocalScanStrategy() *LocalScanStrategy {
|
||||||
return &LocalScanStrategy{}
|
return &LocalScanStrategy{
|
||||||
|
BaseScanStrategy: NewBaseScanStrategy("本地扫描", FilterLocal),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name 返回策略名称
|
// Name 返回策略名称
|
||||||
func (s *LocalScanStrategy) Name() string {
|
func (s *LocalScanStrategy) Name() string {
|
||||||
return "本地扫描"
|
return i18n.GetText("scan_strategy_local_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description 返回策略描述
|
// Description 返回策略描述
|
||||||
func (s *LocalScanStrategy) Description() string {
|
func (s *LocalScanStrategy) Description() string {
|
||||||
return "收集本地系统信息"
|
return i18n.GetText("scan_strategy_local_desc")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute 执行本地扫描策略
|
// Execute 执行本地扫描策略
|
||||||
func (s *LocalScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func (s *LocalScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
common.LogBase("执行本地信息收集")
|
// 输出扫描开始信息
|
||||||
|
s.LogScanStart()
|
||||||
|
|
||||||
// 验证插件配置
|
// 验证插件配置
|
||||||
if err := validateScanPlugins(); err != nil {
|
if err := s.ValidateConfiguration(); err != nil {
|
||||||
common.LogError(err.Error())
|
common.LogError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -50,63 +54,3 @@ func (s *LocalScanStrategy) PrepareTargets(info common.HostInfo) []common.HostIn
|
|||||||
// 本地扫描只使用传入的目标信息,不做额外处理
|
// 本地扫描只使用传入的目标信息,不做额外处理
|
||||||
return []common.HostInfo{info}
|
return []common.HostInfo{info}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlugins 获取本地扫描插件列表
|
|
||||||
func (s *LocalScanStrategy) GetPlugins() ([]string, bool) {
|
|
||||||
// 如果指定了特定插件且不是"all"
|
|
||||||
if common.ScanMode != "" && common.ScanMode != "all" {
|
|
||||||
requestedPlugins := parsePluginList(common.ScanMode)
|
|
||||||
if len(requestedPlugins) == 0 {
|
|
||||||
requestedPlugins = []string{common.ScanMode}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证插件是否存在,不做Local类型过滤
|
|
||||||
var validPlugins []string
|
|
||||||
for _, name := range requestedPlugins {
|
|
||||||
if _, exists := common.PluginManager[name]; exists {
|
|
||||||
validPlugins = append(validPlugins, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return validPlugins, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未指定或使用"all":获取所有插件,由IsPluginApplicable做类型过滤
|
|
||||||
return GetAllPlugins(), false
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogPluginInfo 输出本地扫描插件信息
|
|
||||||
func (s *LocalScanStrategy) LogPluginInfo() {
|
|
||||||
allPlugins, isCustomMode := s.GetPlugins()
|
|
||||||
|
|
||||||
// 如果是自定义模式,直接显示用户指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
common.LogBase(fmt.Sprintf("本地模式: 使用指定插件: %s", strings.Join(allPlugins, ", ")))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在自动模式下,只显示Local类型的插件
|
|
||||||
var applicablePlugins []string
|
|
||||||
for _, pluginName := range allPlugins {
|
|
||||||
plugin, exists := common.PluginManager[pluginName]
|
|
||||||
if exists && plugin.HasType(common.PluginTypeLocal) {
|
|
||||||
applicablePlugins = append(applicablePlugins, pluginName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(applicablePlugins) > 0 {
|
|
||||||
common.LogBase(fmt.Sprintf("本地模式: 使用本地插件: %s", strings.Join(applicablePlugins, ", ")))
|
|
||||||
} else {
|
|
||||||
common.LogBase("本地模式: 未找到可用的本地插件")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPluginApplicable 判断插件是否适用于本地扫描
|
|
||||||
func (s *LocalScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
|
||||||
// 自定义模式下运行所有明确指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// 非自定义模式下,只运行Local类型插件
|
|
||||||
return plugin.HasType(common.PluginTypeLocal)
|
|
||||||
}
|
|
||||||
|
98
Core/PortDiscoveryService.go
Normal file
98
Core/PortDiscoveryService.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
"github.com/shadow1ng/fscan/common/parsers"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
PortDiscoveryService.go - 端口发现服务
|
||||||
|
|
||||||
|
负责主机存活检测、端口扫描等端口发现相关功能,
|
||||||
|
从ServiceScanner中分离出来提高代码可维护性。
|
||||||
|
*/
|
||||||
|
|
||||||
|
// PortDiscoveryService 端口发现服务
|
||||||
|
type PortDiscoveryService struct{}
|
||||||
|
|
||||||
|
// NewPortDiscoveryService 创建端口发现服务
|
||||||
|
func NewPortDiscoveryService() *PortDiscoveryService {
|
||||||
|
return &PortDiscoveryService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscoverTargets 发现目标主机和端口
|
||||||
|
func (p *PortDiscoveryService) DiscoverTargets(hostInput string, baseInfo common.HostInfo) ([]common.HostInfo, error) {
|
||||||
|
// 解析目标主机
|
||||||
|
hosts, err := parsers.ParseIP(hostInput, common.HostsFile, common.ExcludeHosts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(i18n.GetText("parse_error_target_failed"), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetInfos []common.HostInfo
|
||||||
|
|
||||||
|
// 主机存活性检测和端口扫描
|
||||||
|
if len(hosts) > 0 || len(common.HostPort) > 0 {
|
||||||
|
// 主机存活检测
|
||||||
|
if p.shouldPerformLivenessCheck(hosts) {
|
||||||
|
hosts = CheckLive(hosts, false)
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_hosts_count", len(hosts)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 端口扫描
|
||||||
|
alivePorts := p.discoverAlivePorts(hosts)
|
||||||
|
if len(alivePorts) > 0 {
|
||||||
|
targetInfos = p.convertToTargetInfos(alivePorts, baseInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetInfos, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldPerformLivenessCheck 判断是否需要执行存活性检测
|
||||||
|
func (p *PortDiscoveryService) shouldPerformLivenessCheck(hosts []string) bool {
|
||||||
|
return common.DisablePing == false && len(hosts) > 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// discoverAlivePorts 发现存活的端口
|
||||||
|
func (p *PortDiscoveryService) discoverAlivePorts(hosts []string) []string {
|
||||||
|
var alivePorts []string
|
||||||
|
|
||||||
|
// 根据扫描模式选择端口扫描方式
|
||||||
|
if len(hosts) > 0 {
|
||||||
|
alivePorts = EnhancedPortScan(hosts, common.Ports, common.Timeout)
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 合并额外指定的端口
|
||||||
|
if len(common.HostPort) > 0 {
|
||||||
|
alivePorts = append(alivePorts, common.HostPort...)
|
||||||
|
alivePorts = common.RemoveDuplicate(alivePorts)
|
||||||
|
common.HostPort = nil
|
||||||
|
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return alivePorts
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertToTargetInfos 将端口列表转换为目标信息
|
||||||
|
func (p *PortDiscoveryService) convertToTargetInfos(ports []string, baseInfo common.HostInfo) []common.HostInfo {
|
||||||
|
var infos []common.HostInfo
|
||||||
|
|
||||||
|
for _, targetIP := range ports {
|
||||||
|
hostParts := strings.Split(targetIP, ":")
|
||||||
|
if len(hostParts) != 2 {
|
||||||
|
common.LogError(i18n.GetText("parse_error_invalid_target_format", targetIP))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
info := baseInfo
|
||||||
|
info.Host = hostParts[0]
|
||||||
|
info.Ports = hostParts[1]
|
||||||
|
infos = append(infos, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
return infos
|
||||||
|
}
|
@ -1,80 +1,70 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
"github.com/shadow1ng/fscan/common/parsers"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServiceScanStrategy 服务扫描策略
|
// ServiceScanStrategy 服务扫描策略
|
||||||
type ServiceScanStrategy struct{}
|
type ServiceScanStrategy struct {
|
||||||
|
*BaseScanStrategy
|
||||||
|
portDiscovery *PortDiscoveryService
|
||||||
|
}
|
||||||
|
|
||||||
// NewServiceScanStrategy 创建新的服务扫描策略
|
// NewServiceScanStrategy 创建新的服务扫描策略
|
||||||
func NewServiceScanStrategy() *ServiceScanStrategy {
|
func NewServiceScanStrategy() *ServiceScanStrategy {
|
||||||
return &ServiceScanStrategy{}
|
return &ServiceScanStrategy{
|
||||||
|
BaseScanStrategy: NewBaseScanStrategy("服务扫描", FilterService),
|
||||||
|
portDiscovery: NewPortDiscoveryService(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name 返回策略名称
|
// Name 返回策略名称
|
||||||
func (s *ServiceScanStrategy) Name() string {
|
func (s *ServiceScanStrategy) Name() string {
|
||||||
return "服务扫描"
|
return i18n.GetText("scan_strategy_service_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description 返回策略描述
|
// Description 返回策略描述
|
||||||
func (s *ServiceScanStrategy) Description() string {
|
func (s *ServiceScanStrategy) Description() string {
|
||||||
return "扫描主机服务和漏洞"
|
return i18n.GetText("scan_strategy_service_desc")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute 执行服务扫描策略
|
// Execute 执行服务扫描策略
|
||||||
func (s *ServiceScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func (s *ServiceScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
// 验证扫描目标
|
// 验证扫描目标
|
||||||
if info.Host == "" {
|
if info.Host == "" {
|
||||||
common.LogError("未指定扫描目标")
|
common.LogError(i18n.GetText("parse_error_target_empty"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 输出扫描开始信息
|
||||||
|
s.LogScanStart()
|
||||||
|
|
||||||
// 验证插件配置
|
// 验证插件配置
|
||||||
if err := validateScanPlugins(); err != nil {
|
if err := s.ValidateConfiguration(); err != nil {
|
||||||
common.LogError(err.Error())
|
common.LogError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析目标主机
|
|
||||||
hosts, err := parsers.ParseIP(info.Host, common.HostsFile, common.ExcludeHosts)
|
|
||||||
if err != nil {
|
|
||||||
common.LogError(fmt.Sprintf("解析主机错误: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
common.LogBase(i18n.GetText("scan_host_start"))
|
common.LogBase(i18n.GetText("scan_host_start"))
|
||||||
|
|
||||||
// 输出插件信息
|
// 输出插件信息
|
||||||
s.LogPluginInfo()
|
s.LogPluginInfo()
|
||||||
|
|
||||||
// 执行主机扫描流程
|
// 执行主机扫描流程
|
||||||
s.performHostScan(hosts, info, ch, wg)
|
s.performHostScan(info, ch, wg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// performHostScan 执行主机扫描的完整流程
|
// performHostScan 执行主机扫描的完整流程
|
||||||
func (s *ServiceScanStrategy) performHostScan(hosts []string, info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func (s *ServiceScanStrategy) performHostScan(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
var targetInfos []common.HostInfo
|
// 使用端口发现服务发现目标
|
||||||
|
targetInfos, err := s.portDiscovery.DiscoverTargets(info.Host, info)
|
||||||
// 主机存活性检测和端口扫描
|
if err != nil {
|
||||||
if len(hosts) > 0 || len(common.HostPort) > 0 {
|
common.LogError(err.Error())
|
||||||
// 主机存活检测
|
return
|
||||||
if s.shouldPerformLivenessCheck(hosts) {
|
|
||||||
hosts = CheckLive(hosts, false)
|
|
||||||
common.LogBase(fmt.Sprintf("存活主机数量: %d", len(hosts)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 端口扫描
|
|
||||||
alivePorts := s.discoverAlivePorts(hosts)
|
|
||||||
if len(alivePorts) > 0 {
|
|
||||||
targetInfos = s.convertToTargetInfos(alivePorts, info)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 执行漏洞扫描
|
// 执行漏洞扫描
|
||||||
@ -86,161 +76,55 @@ func (s *ServiceScanStrategy) performHostScan(hosts []string, info common.HostIn
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shouldPerformLivenessCheck 判断是否需要执行存活性检测
|
|
||||||
func (s *ServiceScanStrategy) shouldPerformLivenessCheck(hosts []string) bool {
|
|
||||||
return common.DisablePing == false && len(hosts) > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// discoverAlivePorts 发现存活的端口
|
|
||||||
func (s *ServiceScanStrategy) discoverAlivePorts(hosts []string) []string {
|
|
||||||
var alivePorts []string
|
|
||||||
|
|
||||||
// 根据扫描模式选择端口扫描方式
|
|
||||||
if len(hosts) > 0 {
|
|
||||||
alivePorts = EnhancedPortScan(hosts, common.Ports, common.Timeout)
|
|
||||||
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 合并额外指定的端口
|
|
||||||
if len(common.HostPort) > 0 {
|
|
||||||
alivePorts = append(alivePorts, common.HostPort...)
|
|
||||||
alivePorts = common.RemoveDuplicate(alivePorts)
|
|
||||||
common.HostPort = nil
|
|
||||||
common.LogBase(i18n.GetText("scan_alive_ports_count", len(alivePorts)))
|
|
||||||
}
|
|
||||||
|
|
||||||
return alivePorts
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrepareTargets 准备目标信息
|
// PrepareTargets 准备目标信息
|
||||||
func (s *ServiceScanStrategy) PrepareTargets(info common.HostInfo) []common.HostInfo {
|
func (s *ServiceScanStrategy) PrepareTargets(info common.HostInfo) []common.HostInfo {
|
||||||
// 解析目标主机
|
// 使用端口发现服务发现目标
|
||||||
hosts, err := parsers.ParseIP(info.Host, common.HostsFile, common.ExcludeHosts)
|
targetInfos, err := s.portDiscovery.DiscoverTargets(info.Host, info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.LogError(fmt.Sprintf("解析主机错误: %v", err))
|
common.LogError(err.Error())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var targetInfos []common.HostInfo
|
|
||||||
|
|
||||||
// 主机存活性检测和端口扫描
|
|
||||||
if len(hosts) > 0 || len(common.HostPort) > 0 {
|
|
||||||
// 主机存活检测
|
|
||||||
if s.shouldPerformLivenessCheck(hosts) {
|
|
||||||
hosts = CheckLive(hosts, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 端口扫描
|
|
||||||
alivePorts := s.discoverAlivePorts(hosts)
|
|
||||||
if len(alivePorts) > 0 {
|
|
||||||
targetInfos = s.convertToTargetInfos(alivePorts, info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetInfos
|
return targetInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertToTargetInfos 将端口列表转换为目标信息
|
|
||||||
func (s *ServiceScanStrategy) convertToTargetInfos(ports []string, baseInfo common.HostInfo) []common.HostInfo {
|
|
||||||
var infos []common.HostInfo
|
|
||||||
|
|
||||||
for _, targetIP := range ports {
|
|
||||||
hostParts := strings.Split(targetIP, ":")
|
|
||||||
if len(hostParts) != 2 {
|
|
||||||
common.LogError(fmt.Sprintf("无效的目标地址格式: %s", targetIP))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
info := baseInfo
|
|
||||||
info.Host = hostParts[0]
|
|
||||||
info.Ports = hostParts[1]
|
|
||||||
infos = append(infos, info)
|
|
||||||
}
|
|
||||||
|
|
||||||
return infos
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPlugins 获取服务扫描插件列表
|
|
||||||
func (s *ServiceScanStrategy) GetPlugins() ([]string, bool) {
|
|
||||||
// 如果指定了插件列表且不是"all"
|
|
||||||
if common.ScanMode != "" && common.ScanMode != "all" {
|
|
||||||
plugins := parsePluginList(common.ScanMode)
|
|
||||||
if len(plugins) > 0 {
|
|
||||||
return plugins, true
|
|
||||||
}
|
|
||||||
return []string{common.ScanMode}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未指定或使用"all":获取所有插件,由IsPluginApplicable做类型过滤
|
|
||||||
return GetAllPlugins(), false
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogPluginInfo 输出服务扫描插件信息
|
|
||||||
func (s *ServiceScanStrategy) LogPluginInfo() {
|
|
||||||
allPlugins, isCustomMode := s.GetPlugins()
|
|
||||||
|
|
||||||
// 如果是自定义模式,直接显示用户指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
common.LogBase(fmt.Sprintf("使用指定插件: %s", strings.Join(allPlugins, ", ")))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在自动模式下,过滤掉本地插件,只显示服务类型插件
|
|
||||||
var applicablePlugins []string
|
|
||||||
for _, pluginName := range allPlugins {
|
|
||||||
plugin, exists := common.PluginManager[pluginName]
|
|
||||||
if exists && !plugin.HasType(common.PluginTypeLocal) {
|
|
||||||
applicablePlugins = append(applicablePlugins, pluginName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(applicablePlugins) > 0 {
|
|
||||||
common.LogBase(fmt.Sprintf("使用服务插件: %s", strings.Join(applicablePlugins, ", ")))
|
|
||||||
} else {
|
|
||||||
common.LogBase(i18n.GetText("scan_no_service_plugins"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogVulnerabilityPluginInfo 输出漏洞扫描插件信息
|
// LogVulnerabilityPluginInfo 输出漏洞扫描插件信息
|
||||||
func (s *ServiceScanStrategy) LogVulnerabilityPluginInfo(targets []common.HostInfo) {
|
func (s *ServiceScanStrategy) LogVulnerabilityPluginInfo(targets []common.HostInfo) {
|
||||||
allPlugins, isCustomMode := s.GetPlugins()
|
allPlugins, isCustomMode := s.GetPlugins()
|
||||||
|
|
||||||
// 获取实际会被使用的插件列表
|
// 收集所有目标端口用于插件适用性检查
|
||||||
var vulnerabilityPlugins []string
|
portSet := make(map[int]bool)
|
||||||
pluginUsed := make(map[string]bool)
|
|
||||||
|
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
targetPort := 0
|
|
||||||
if target.Ports != "" {
|
if target.Ports != "" {
|
||||||
targetPort, _ = strconv.Atoi(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
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pluginName := range allPlugins {
|
// 检查插件是否对任何目标端口适用
|
||||||
plugin, exists := common.PluginManager[pluginName]
|
if s.isPluginApplicableToAnyPort(plugin, portSet, isCustomMode) {
|
||||||
if !exists {
|
vulnerabilityPlugins = append(vulnerabilityPlugins, pluginName)
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查插件是否适用于当前目标(使用与ExecuteScanTasks相同的逻辑)
|
|
||||||
if s.IsPluginApplicable(plugin, targetPort, isCustomMode) {
|
|
||||||
if !pluginUsed[pluginName] {
|
|
||||||
vulnerabilityPlugins = append(vulnerabilityPlugins, pluginName)
|
|
||||||
pluginUsed[pluginName] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 输出插件信息
|
// 输出插件信息
|
||||||
if len(vulnerabilityPlugins) > 0 {
|
if len(vulnerabilityPlugins) > 0 {
|
||||||
common.LogBase(fmt.Sprintf(i18n.GetText("scan_vulnerability_plugins"), strings.Join(vulnerabilityPlugins, ", ")))
|
common.LogBase(i18n.GetText("scan_vulnerability_plugins", strings.Join(vulnerabilityPlugins, ", ")))
|
||||||
} else {
|
} else {
|
||||||
common.LogBase(i18n.GetText("scan_no_vulnerability_plugins"))
|
common.LogBase(i18n.GetText("scan_no_vulnerability_plugins"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsPluginApplicable 判断插件是否适用于服务扫描
|
// isPluginApplicableToAnyPort 检查插件是否对任何端口适用(性能优化)
|
||||||
func (s *ServiceScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
func (s *ServiceScanStrategy) isPluginApplicableToAnyPort(plugin common.ScanPlugin, portSet map[int]bool, isCustomMode bool) bool {
|
||||||
// 自定义模式下运行所有明确指定的插件
|
// 自定义模式下运行所有明确指定的插件
|
||||||
if isCustomMode {
|
if isCustomMode {
|
||||||
return true
|
return true
|
||||||
@ -251,11 +135,17 @@ func (s *ServiceScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targe
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查端口是否匹配
|
// 无端口限制的插件适用于所有端口
|
||||||
if len(plugin.Ports) > 0 && targetPort > 0 {
|
if len(plugin.Ports) == 0 {
|
||||||
return plugin.HasPort(targetPort)
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 无端口限制的插件或适用于服务扫描的插件
|
// 有端口限制的插件:检查是否匹配任何目标端口
|
||||||
return len(plugin.Ports) == 0 || plugin.HasType(common.PluginTypeService)
|
for port := range portSet {
|
||||||
|
if plugin.HasPort(port) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1,36 +1,41 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WebScanStrategy Web扫描策略
|
// WebScanStrategy Web扫描策略
|
||||||
type WebScanStrategy struct{}
|
type WebScanStrategy struct {
|
||||||
|
*BaseScanStrategy
|
||||||
|
}
|
||||||
|
|
||||||
// NewWebScanStrategy 创建新的Web扫描策略
|
// NewWebScanStrategy 创建新的Web扫描策略
|
||||||
func NewWebScanStrategy() *WebScanStrategy {
|
func NewWebScanStrategy() *WebScanStrategy {
|
||||||
return &WebScanStrategy{}
|
return &WebScanStrategy{
|
||||||
|
BaseScanStrategy: NewBaseScanStrategy("Web扫描", FilterWeb),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name 返回策略名称
|
// Name 返回策略名称
|
||||||
func (s *WebScanStrategy) Name() string {
|
func (s *WebScanStrategy) Name() string {
|
||||||
return "Web扫描"
|
return i18n.GetText("scan_strategy_web_name")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description 返回策略描述
|
// Description 返回策略描述
|
||||||
func (s *WebScanStrategy) Description() string {
|
func (s *WebScanStrategy) Description() string {
|
||||||
return "扫描Web应用漏洞和信息"
|
return i18n.GetText("scan_strategy_web_desc")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute 执行Web扫描策略
|
// Execute 执行Web扫描策略
|
||||||
func (s *WebScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
func (s *WebScanStrategy) Execute(info common.HostInfo, ch *chan struct{}, wg *sync.WaitGroup) {
|
||||||
common.LogBase("开始Web扫描")
|
// 输出扫描开始信息
|
||||||
|
s.LogScanStart()
|
||||||
|
|
||||||
// 验证插件配置
|
// 验证插件配置
|
||||||
if err := validateScanPlugins(); err != nil {
|
if err := s.ValidateConfiguration(); err != nil {
|
||||||
common.LogError(err.Error())
|
common.LogError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -62,64 +67,3 @@ func (s *WebScanStrategy) PrepareTargets(baseInfo common.HostInfo) []common.Host
|
|||||||
return targetInfos
|
return targetInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlugins 获取Web扫描插件列表
|
|
||||||
func (s *WebScanStrategy) GetPlugins() ([]string, bool) {
|
|
||||||
// 如果指定了自定义插件并且不是"all"
|
|
||||||
if common.ScanMode != "" && common.ScanMode != "all" {
|
|
||||||
requestedPlugins := parsePluginList(common.ScanMode)
|
|
||||||
if len(requestedPlugins) == 0 {
|
|
||||||
requestedPlugins = []string{common.ScanMode}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证插件是否存在,不做Web类型过滤
|
|
||||||
var validPlugins []string
|
|
||||||
for _, name := range requestedPlugins {
|
|
||||||
if _, exists := common.PluginManager[name]; exists {
|
|
||||||
validPlugins = append(validPlugins, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(validPlugins) > 0 {
|
|
||||||
return validPlugins, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 未指定或使用"all":获取所有插件,由IsPluginApplicable做类型过滤
|
|
||||||
return GetAllPlugins(), false
|
|
||||||
}
|
|
||||||
|
|
||||||
// LogPluginInfo 输出Web扫描插件信息
|
|
||||||
func (s *WebScanStrategy) LogPluginInfo() {
|
|
||||||
allPlugins, isCustomMode := s.GetPlugins()
|
|
||||||
|
|
||||||
// 如果是自定义模式,直接显示用户指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
common.LogBase(fmt.Sprintf("Web扫描模式: 使用指定插件: %s", strings.Join(allPlugins, ", ")))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在自动模式下,只显示Web类型的插件
|
|
||||||
var applicablePlugins []string
|
|
||||||
for _, pluginName := range allPlugins {
|
|
||||||
plugin, exists := common.PluginManager[pluginName]
|
|
||||||
if exists && plugin.HasType(common.PluginTypeWeb) {
|
|
||||||
applicablePlugins = append(applicablePlugins, pluginName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(applicablePlugins) > 0 {
|
|
||||||
common.LogBase(fmt.Sprintf("Web扫描模式: 使用Web插件: %s", strings.Join(applicablePlugins, ", ")))
|
|
||||||
} else {
|
|
||||||
common.LogBase("Web扫描模式: 未找到可用的Web插件")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPluginApplicable 判断插件是否适用于Web扫描
|
|
||||||
func (s *WebScanStrategy) IsPluginApplicable(plugin common.ScanPlugin, targetPort int, isCustomMode bool) bool {
|
|
||||||
// 自定义模式下运行所有明确指定的插件
|
|
||||||
if isCustomMode {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
// 非自定义模式下,只运行Web类型插件
|
|
||||||
return plugin.HasType(common.PluginTypeWeb)
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user