mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 05:56:46 +08:00

将复杂的三文件插件架构(connector/exploiter/plugin)重构为简化的单文件插件架构, 大幅减少代码重复和维护成本,提升插件开发效率。 主要改进: • 将每个服务插件从3个文件简化为1个文件 • 删除过度设计的工厂模式、适配器模式等抽象层 • 消除plugins/services/、plugins/adapters/、plugins/base/复杂目录结构 • 实现直接的插件注册机制,提升系统简洁性 • 保持完全向后兼容,所有扫描功能和输出格式不变 重构统计: • 删除文件:100+个复杂架构文件 • 新增文件:20个简化的单文件插件 • 代码减少:每个插件减少60-80%代码量 • 功能增强:所有插件包含完整扫描和利用功能 已重构插件: MySQL, SSH, Redis, MongoDB, PostgreSQL, MSSQL, Oracle, Neo4j, Memcached, RabbitMQ, ActiveMQ, Cassandra, FTP, Kafka, LDAP, Rsync, SMTP, SNMP, Telnet, VNC 验证通过: 新系统编译运行正常,所有插件功能验证通过
192 lines
5.0 KiB
Go
192 lines
5.0 KiB
Go
package core
|
||
|
||
import (
|
||
"github.com/shadow1ng/fscan/common"
|
||
"github.com/shadow1ng/fscan/common/i18n"
|
||
"github.com/shadow1ng/fscan/plugins"
|
||
"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 servicePlugins []string
|
||
|
||
// 检查新插件架构
|
||
for _, pluginName := range allPlugins {
|
||
// 首先检查新插件架构
|
||
if plugin := plugins.GetPlugin(pluginName); plugin != nil {
|
||
// 检查端口匹配
|
||
if s.isNewPluginApplicableToAnyPort(plugin, portSet, isCustomMode) {
|
||
servicePlugins = append(servicePlugins, pluginName)
|
||
}
|
||
continue
|
||
}
|
||
|
||
// 然后检查传统插件系统
|
||
plugin, exists := common.PluginManager[pluginName]
|
||
if !exists {
|
||
continue
|
||
}
|
||
|
||
// 检查传统插件是否对任何目标端口适用
|
||
if s.isPluginApplicableToAnyPort(plugin, portSet, isCustomMode) {
|
||
servicePlugins = append(servicePlugins, pluginName)
|
||
}
|
||
}
|
||
|
||
// 输出插件信息
|
||
if len(servicePlugins) > 0 {
|
||
common.LogBase(i18n.GetText("scan_service_plugins", strings.Join(servicePlugins, ", ")))
|
||
} else {
|
||
common.LogBase(i18n.GetText("scan_no_service_plugins"))
|
||
}
|
||
}
|
||
|
||
// isPluginApplicableToAnyPort 检查插件是否对任何端口适用(性能优化)
|
||
func (s *ServiceScanStrategy) isPluginApplicableToAnyPort(plugin common.ScanPlugin, portSet map[int]bool, isCustomMode bool) bool {
|
||
// 自定义模式下运行所有明确指定的插件
|
||
if isCustomMode {
|
||
return true
|
||
}
|
||
|
||
// 服务扫描排除本地插件,但保留Web插件(有智能检测)
|
||
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
|
||
}
|
||
|
||
// isNewPluginApplicableToAnyPort 检查新插件架构的插件是否对任何端口适用
|
||
func (s *ServiceScanStrategy) isNewPluginApplicableToAnyPort(plugin plugins.Plugin, portSet map[int]bool, isCustomMode bool) bool {
|
||
// 自定义模式下运行所有明确指定的插件
|
||
if isCustomMode {
|
||
return true
|
||
}
|
||
|
||
// 获取插件支持的端口
|
||
pluginPorts := plugin.GetPorts()
|
||
|
||
// 无端口限制的插件适用于所有端口
|
||
if len(pluginPorts) == 0 {
|
||
return true
|
||
}
|
||
|
||
// 有端口限制的插件:检查是否匹配任何目标端口
|
||
for port := range portSet {
|
||
for _, pluginPort := range pluginPorts {
|
||
if pluginPort == port {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|