fscan/Plugins/adapter/plugin_adapter.go
ZacharyZcR b346e6bdc1 feat: 完善插件系统i18n国际化支持
- 修复重复输出问题:适配器层改为debug输出,避免与插件层重复
- 修复格式化错误:修正SaveExploitResult中的端口格式化问题
- 新增利用方法名称i18n:添加GetExploitMethodName函数支持方法名本地化
- 扩展i18n消息模板:新增利用方法执行、MySQL/Redis专用消息模板
- 完善exploiter国际化:所有利用方法和结果消息支持中英文切换
- 优化用户体验:利用方法显示从"information_gathering"变为"信息收集"
2025-08-07 12:30:17 +08:00

165 lines
4.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package adapter
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
}