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

问题: - "使用服务扫描插件" 只显示一个错误插件名(如ldap) - 原因:只检查第一个端口来判断所有插件适用性 - 实际扫描有多个端口,每个端口适用不同插件组合 修复: - 改为检查所有发现端口的插件适用性匹配 - 使用Set去重,收集适用于任意端口的所有插件 - 正确显示实际会被使用的插件列表 修复前: 使用服务扫描插件: ldap 修复后: 使用服务扫描插件: webtitle, ssh, mysql, smtp, webpoc 验证: - SSH插件 → 端口22 ✓ - SMTP插件 → 端口25 ✓ - MySQL插件 → 端口3306 ✓ - WebTitle/WebPOC → 端口8080 ✓
212 lines
5.7 KiB
Go
212 lines
5.7 KiB
Go
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"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(),
|
|
}
|
|
}
|
|
|
|
// LogPluginInfo 重写以提供基于端口的插件过滤
|
|
func (s *ServiceScanStrategy) LogPluginInfo() {
|
|
// 需要从命令行参数获取端口信息来进行过滤
|
|
// 如果没有指定端口,使用默认端口进行过滤显示
|
|
if common.Ports == "" || common.Ports == "all" {
|
|
// 默认端口扫描:显示所有插件
|
|
s.BaseScanStrategy.LogPluginInfo()
|
|
} else {
|
|
// 指定端口扫描:只显示匹配的插件
|
|
s.showPluginsForSpecifiedPorts()
|
|
}
|
|
}
|
|
|
|
// showPluginsForSpecifiedPorts 显示指定端口的匹配插件
|
|
func (s *ServiceScanStrategy) showPluginsForSpecifiedPorts() {
|
|
allPlugins, isCustomMode := s.GetPlugins()
|
|
|
|
// 解析端口
|
|
ports := s.parsePortList(common.Ports)
|
|
if len(ports) == 0 {
|
|
s.BaseScanStrategy.LogPluginInfo()
|
|
return
|
|
}
|
|
|
|
// 收集所有匹配的插件(去重)
|
|
pluginSet := make(map[string]bool)
|
|
for _, port := range ports {
|
|
for _, pluginName := range allPlugins {
|
|
if s.pluginExists(pluginName) {
|
|
if s.IsPluginApplicableByName(pluginName, "127.0.0.1", port, isCustomMode) {
|
|
pluginSet[pluginName] = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 转换为列表
|
|
var applicablePlugins []string
|
|
for pluginName := range pluginSet {
|
|
applicablePlugins = append(applicablePlugins, pluginName)
|
|
}
|
|
|
|
// 输出结果
|
|
if len(applicablePlugins) > 0 {
|
|
if isCustomMode {
|
|
common.LogBase(fmt.Sprintf("服务插件: 自定义指定 (%s)", strings.Join(applicablePlugins, ", ")))
|
|
} else {
|
|
common.LogBase(fmt.Sprintf("服务插件: %s", strings.Join(applicablePlugins, ", ")))
|
|
}
|
|
} else {
|
|
common.LogBase("服务插件: 无可用插件")
|
|
}
|
|
}
|
|
|
|
// parsePortList 解析端口列表
|
|
func (s *ServiceScanStrategy) parsePortList(portStr string) []int {
|
|
if portStr == "" || portStr == "all" {
|
|
return []int{}
|
|
}
|
|
|
|
var ports []int
|
|
parts := strings.Split(portStr, ",")
|
|
for _, part := range parts {
|
|
part = strings.TrimSpace(part)
|
|
if port, err := strconv.Atoi(part); err == nil {
|
|
ports = append(ports, port)
|
|
}
|
|
}
|
|
return ports
|
|
}
|
|
|
|
// 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
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取实际会被使用的插件列表(考虑所有发现端口的匹配)
|
|
servicePluginSet := make(map[string]bool)
|
|
|
|
// 提取所有目标端口用于插件适用性检查
|
|
var allPorts []int
|
|
for port := range portSet {
|
|
allPorts = append(allPorts, port)
|
|
}
|
|
|
|
for _, pluginName := range allPlugins {
|
|
// 使用统一插件系统检查插件存在性
|
|
if s.pluginExists(pluginName) {
|
|
// 检查插件是否适用于任意一个发现的端口
|
|
for _, port := range allPorts {
|
|
if s.IsPluginApplicableByName(pluginName, "127.0.0.1", port, isCustomMode) {
|
|
servicePluginSet[pluginName] = true
|
|
break // 只要适用于一个端口就添加
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 转换为切片
|
|
var servicePlugins []string
|
|
for pluginName := range servicePluginSet {
|
|
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"))
|
|
}
|
|
}
|
|
|