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

- 移动adapters目录到plugins下统一管理 - 删除已迁移的老版本插件文件,避免代码重复 - 更新所有legacy适配器引用,统一使用legacy目录下的源文件 - 新增FindNet插件的legacy适配器,支持135端口RPC扫描 - 修复包导入路径,确保适配器正常工作 - 清理插件目录结构,分离新架构插件和legacy插件
165 lines
4.9 KiB
Go
165 lines
4.9 KiB
Go
package adapters
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"github.com/shadow1ng/fscan/common"
|
||
"github.com/shadow1ng/fscan/common/i18n"
|
||
"github.com/shadow1ng/fscan/common/output"
|
||
"github.com/shadow1ng/fscan/plugins/base"
|
||
"time"
|
||
|
||
// 导入新插件以触发注册
|
||
_ "github.com/shadow1ng/fscan/plugins/services/mysql"
|
||
_ "github.com/shadow1ng/fscan/plugins/services/redis"
|
||
_ "github.com/shadow1ng/fscan/plugins/services/ssh"
|
||
)
|
||
|
||
// PluginAdapter 插件适配器,将新插件架构与旧系统集成
|
||
type PluginAdapter struct {
|
||
registry *base.PluginRegistry
|
||
}
|
||
|
||
// NewPluginAdapter 创建插件适配器
|
||
func NewPluginAdapter() *PluginAdapter {
|
||
return &PluginAdapter{
|
||
registry: base.GlobalPluginRegistry,
|
||
}
|
||
}
|
||
|
||
// AdaptPluginScan 适配插件扫描调用
|
||
// 将传统的插件扫描函数调用转换为新架构的插件调用
|
||
func (a *PluginAdapter) AdaptPluginScan(pluginName string, info *common.HostInfo) error {
|
||
// 创建插件实例
|
||
plugin, err := a.registry.Create(pluginName)
|
||
if err != nil {
|
||
// 如果新架构中没有该插件,返回错误让旧系统处理
|
||
return fmt.Errorf("plugin %s not found in new architecture: %v", pluginName, err)
|
||
}
|
||
|
||
// 初始化插件
|
||
if err := plugin.Initialize(); err != nil {
|
||
return fmt.Errorf("plugin %s initialization failed: %v", pluginName, err)
|
||
}
|
||
|
||
// 设置全局超时上下文
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(common.GlobalTimeout)*time.Second)
|
||
defer cancel()
|
||
|
||
// 执行扫描
|
||
result, err := plugin.Scan(ctx, info)
|
||
if err != nil {
|
||
common.LogError(fmt.Sprintf("Plugin %s scan failed: %v", pluginName, err))
|
||
return err
|
||
}
|
||
|
||
// 如果扫描成功,记录结果
|
||
if result != nil && result.Success {
|
||
target := fmt.Sprintf("%s:%s", info.Host, info.Ports)
|
||
|
||
// 适配器层不输出扫描结果,由插件层负责输出
|
||
// 这避免了重复输出的问题
|
||
common.LogDebug(fmt.Sprintf("插件 %s 适配成功: %s", pluginName, target))
|
||
|
||
// 保存结果到文件
|
||
a.saveResult(info, result, pluginName)
|
||
|
||
// 如果有漏洞信息,也记录下来
|
||
for _, vuln := range result.Vulnerabilities {
|
||
common.LogError(fmt.Sprintf("%s vulnerability found: %s - %s",
|
||
pluginName, vuln.ID, vuln.Description))
|
||
}
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// saveResult 保存扫描结果
|
||
func (a *PluginAdapter) saveResult(info *common.HostInfo, result *base.ScanResult, pluginName string) {
|
||
// 使用原有的结果保存机制
|
||
|
||
vulnResult := &output.ScanResult{
|
||
Time: time.Now(),
|
||
Type: output.TypeVuln,
|
||
Target: info.Host,
|
||
Status: "vulnerable",
|
||
Details: map[string]interface{}{
|
||
"plugin": pluginName,
|
||
"port": info.Ports,
|
||
"host": info.Host,
|
||
},
|
||
}
|
||
|
||
if len(result.Credentials) > 0 {
|
||
cred := result.Credentials[0]
|
||
if cred.Username != "" {
|
||
vulnResult.Details["username"] = cred.Username
|
||
vulnResult.Details["password"] = cred.Password
|
||
vulnResult.Details["credentials"] = fmt.Sprintf("%s:%s", cred.Username, cred.Password)
|
||
} else {
|
||
vulnResult.Details["password"] = cred.Password
|
||
vulnResult.Details["credentials"] = cred.Password
|
||
}
|
||
} else {
|
||
// 未授权访问
|
||
vulnResult.Details["type"] = "unauthorized"
|
||
}
|
||
|
||
// 保存结果
|
||
common.SaveResult(vulnResult)
|
||
}
|
||
|
||
// IsPluginSupported 检查插件是否在新架构中支持
|
||
func (a *PluginAdapter) IsPluginSupported(pluginName string) bool {
|
||
plugins := a.registry.GetAll()
|
||
for _, name := range plugins {
|
||
if name == pluginName {
|
||
return true
|
||
}
|
||
}
|
||
return false
|
||
}
|
||
|
||
// GetSupportedPlugins 获取新架构支持的插件列表
|
||
func (a *PluginAdapter) GetSupportedPlugins() []string {
|
||
return a.registry.GetAll()
|
||
}
|
||
|
||
// GetPluginMetadata 获取插件元数据
|
||
func (a *PluginAdapter) GetPluginMetadata(pluginName string) (*base.PluginMetadata, error) {
|
||
metadata := a.registry.GetMetadata(pluginName)
|
||
if metadata == nil {
|
||
return nil, fmt.Errorf("plugin %s not found", pluginName)
|
||
}
|
||
return metadata, nil
|
||
}
|
||
|
||
// =============================================================================
|
||
// 全局适配器实例
|
||
// =============================================================================
|
||
|
||
// GlobalAdapter 全局插件适配器实例
|
||
var GlobalAdapter = NewPluginAdapter()
|
||
|
||
// =============================================================================
|
||
// 便捷函数
|
||
// =============================================================================
|
||
|
||
// TryNewArchitecture 尝试使用新架构执行插件扫描
|
||
// 如果新架构支持该插件,则使用新架构;否则返回false让调用方使用旧插件
|
||
func TryNewArchitecture(pluginName string, info *common.HostInfo) bool {
|
||
if !GlobalAdapter.IsPluginSupported(pluginName) {
|
||
common.LogDebug(i18n.GetText("plugin_legacy_using", pluginName))
|
||
return false
|
||
}
|
||
|
||
common.LogDebug(i18n.GetText("plugin_new_arch_trying", pluginName))
|
||
err := GlobalAdapter.AdaptPluginScan(pluginName, info)
|
||
if err != nil {
|
||
common.LogError(i18n.GetText("plugin_new_arch_fallback", pluginName, err))
|
||
return false
|
||
}
|
||
|
||
common.LogDebug(i18n.GetText("plugin_new_arch_success", pluginName))
|
||
return true
|
||
} |