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

- 重构SSH/MySQL/Redis插件超时控制,移除第三方库超时依赖 - 统一使用Go Context超时机制,提升超时控制可靠性和精确度 - 扩展MySQL/Redis/SSH插件默认端口支持,提升扫描覆盖率 - 修复插件系统中ConcurrentScanConfig超时配置缺失问题 - 优化插件检测逻辑,正确识别新架构插件并显示准确状态信息 - 解决插件在错误端口上长时间等待问题,显著提升扫描效率
259 lines
6.6 KiB
Go
259 lines
6.6 KiB
Go
package base
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
"github.com/shadow1ng/fscan/common"
|
|
"github.com/shadow1ng/fscan/common/i18n"
|
|
)
|
|
|
|
// =============================================================================
|
|
// 完整插件基础实现
|
|
// =============================================================================
|
|
|
|
// BasePlugin 基础插件实现,组合扫描和利用功能
|
|
type BasePlugin struct {
|
|
*BaseScanner
|
|
*BaseExploiter
|
|
metadata *PluginMetadata
|
|
initialized bool
|
|
}
|
|
|
|
// NewBasePlugin 创建基础插件
|
|
func NewBasePlugin(metadata *PluginMetadata) *BasePlugin {
|
|
return &BasePlugin{
|
|
BaseScanner: NewBaseScanner(metadata.Name, metadata),
|
|
BaseExploiter: NewBaseExploiter(metadata.Name),
|
|
metadata: metadata,
|
|
initialized: false,
|
|
}
|
|
}
|
|
|
|
// Initialize 初始化插件
|
|
func (p *BasePlugin) Initialize() error {
|
|
if p.initialized {
|
|
return nil
|
|
}
|
|
|
|
// 执行插件特定的初始化逻辑
|
|
common.LogDebug(i18n.GetText("plugin_init", p.metadata.Name))
|
|
|
|
p.initialized = true
|
|
return nil
|
|
}
|
|
|
|
// GetMetadata 获取插件元数据
|
|
func (p *BasePlugin) GetMetadata() *PluginMetadata {
|
|
return p.metadata
|
|
}
|
|
|
|
// =============================================================================
|
|
// 通用插件实现模板
|
|
// =============================================================================
|
|
|
|
// ServicePlugin 服务插件模板 - 提供常见的服务扫描模式
|
|
type ServicePlugin struct {
|
|
*BasePlugin
|
|
credentialScanner CredentialScanner
|
|
serviceConnector ServiceConnector
|
|
}
|
|
|
|
// ServiceConnector 服务连接器接口
|
|
type ServiceConnector interface {
|
|
// Connect 连接到服务
|
|
Connect(ctx context.Context, info *common.HostInfo) (interface{}, error)
|
|
|
|
// Authenticate 认证
|
|
Authenticate(ctx context.Context, conn interface{}, cred *Credential) error
|
|
|
|
// Close 关闭连接
|
|
Close(conn interface{}) error
|
|
}
|
|
|
|
// NewServicePlugin 创建服务插件
|
|
func NewServicePlugin(metadata *PluginMetadata, connector ServiceConnector) *ServicePlugin {
|
|
plugin := &ServicePlugin{
|
|
BasePlugin: NewBasePlugin(metadata),
|
|
serviceConnector: connector,
|
|
}
|
|
|
|
// 设置自己为凭据扫描器
|
|
plugin.credentialScanner = plugin
|
|
|
|
return plugin
|
|
}
|
|
|
|
// Scan 服务扫描实现
|
|
func (p *ServicePlugin) Scan(ctx context.Context, info *common.HostInfo) (*ScanResult, error) {
|
|
// 检查是否禁用暴力破解
|
|
if common.DisableBrute {
|
|
return &ScanResult{
|
|
Success: false,
|
|
Error: fmt.Errorf(i18n.GetText("plugin_brute_disabled")),
|
|
}, nil
|
|
}
|
|
|
|
// 生成凭据列表
|
|
credentials := p.generateCredentials()
|
|
if len(credentials) == 0 {
|
|
return &ScanResult{
|
|
Success: false,
|
|
Error: fmt.Errorf(i18n.GetText("plugin_no_credentials")),
|
|
}, nil
|
|
}
|
|
|
|
// 执行并发扫描
|
|
config := &ConcurrentScanConfig{
|
|
MaxConcurrent: common.ModuleThreadNum,
|
|
Timeout: time.Duration(common.Timeout) * time.Second,
|
|
MaxRetries: common.MaxRetries,
|
|
}
|
|
|
|
return ConcurrentCredentialScan(ctx, p.credentialScanner, info, credentials, config)
|
|
}
|
|
|
|
// ScanCredential 实现CredentialScanner接口
|
|
func (p *ServicePlugin) ScanCredential(ctx context.Context, info *common.HostInfo, cred *Credential) (*ScanResult, error) {
|
|
// 连接到服务
|
|
conn, err := p.serviceConnector.Connect(ctx, info)
|
|
if err != nil {
|
|
return &ScanResult{
|
|
Success: false,
|
|
Error: fmt.Errorf("连接失败: %v", err),
|
|
}, nil
|
|
}
|
|
defer p.serviceConnector.Close(conn)
|
|
|
|
// 尝试认证
|
|
err = p.serviceConnector.Authenticate(ctx, conn, cred)
|
|
if err != nil {
|
|
return &ScanResult{
|
|
Success: false,
|
|
Error: fmt.Errorf("认证失败: %v", err),
|
|
}, nil
|
|
}
|
|
|
|
// 认证成功
|
|
result := &ScanResult{
|
|
Success: true,
|
|
Service: p.metadata.Name,
|
|
Credentials: []*Credential{cred},
|
|
Extra: make(map[string]interface{}),
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// generateCredentials 生成凭据列表(需要子类重写)
|
|
func (p *ServicePlugin) generateCredentials() []*Credential {
|
|
// 默认实现:从通用字典生成
|
|
serviceName := p.metadata.Name
|
|
usernames := common.Userdict[serviceName]
|
|
if len(usernames) == 0 {
|
|
usernames = []string{"admin", "root", serviceName}
|
|
}
|
|
|
|
return GenerateCredentials(usernames, common.Passwords)
|
|
}
|
|
|
|
// GetServiceConnector 获取服务连接器(提供给子插件访问)
|
|
func (p *ServicePlugin) GetServiceConnector() ServiceConnector {
|
|
return p.serviceConnector
|
|
}
|
|
|
|
// =============================================================================
|
|
// 插件工厂
|
|
// =============================================================================
|
|
|
|
// PluginFactory 插件工厂接口
|
|
type PluginFactory interface {
|
|
CreatePlugin() Plugin
|
|
GetMetadata() *PluginMetadata
|
|
}
|
|
|
|
// SimplePluginFactory 简单插件工厂
|
|
type SimplePluginFactory struct {
|
|
metadata *PluginMetadata
|
|
creator func() Plugin
|
|
}
|
|
|
|
// NewSimplePluginFactory 创建简单插件工厂
|
|
func NewSimplePluginFactory(metadata *PluginMetadata, creator func() Plugin) *SimplePluginFactory {
|
|
return &SimplePluginFactory{
|
|
metadata: metadata,
|
|
creator: creator,
|
|
}
|
|
}
|
|
|
|
// CreatePlugin 创建插件实例
|
|
func (f *SimplePluginFactory) CreatePlugin() Plugin {
|
|
return f.creator()
|
|
}
|
|
|
|
// GetMetadata 获取插件元数据
|
|
func (f *SimplePluginFactory) GetMetadata() *PluginMetadata {
|
|
return f.metadata
|
|
}
|
|
|
|
// =============================================================================
|
|
// 插件注册管理器
|
|
// =============================================================================
|
|
|
|
// PluginRegistry 插件注册表
|
|
type PluginRegistry struct {
|
|
factories map[string]PluginFactory
|
|
}
|
|
|
|
// NewPluginRegistry 创建插件注册表
|
|
func NewPluginRegistry() *PluginRegistry {
|
|
return &PluginRegistry{
|
|
factories: make(map[string]PluginFactory),
|
|
}
|
|
}
|
|
|
|
// Register 注册插件工厂
|
|
func (r *PluginRegistry) Register(name string, factory PluginFactory) {
|
|
r.factories[name] = factory
|
|
}
|
|
|
|
// Create 创建插件实例
|
|
func (r *PluginRegistry) Create(name string) (Plugin, error) {
|
|
factory, exists := r.factories[name]
|
|
if !exists {
|
|
return nil, fmt.Errorf("插件 %s 未注册", name)
|
|
}
|
|
|
|
plugin := factory.CreatePlugin()
|
|
if err := plugin.Initialize(); err != nil {
|
|
return nil, fmt.Errorf("插件初始化失败: %v", err)
|
|
}
|
|
|
|
return plugin, nil
|
|
}
|
|
|
|
// GetAll 获取所有注册的插件名称
|
|
func (r *PluginRegistry) GetAll() []string {
|
|
names := make([]string, 0, len(r.factories))
|
|
for name := range r.factories {
|
|
names = append(names, name)
|
|
}
|
|
return names
|
|
}
|
|
|
|
// GetMetadata 获取插件元数据
|
|
func (r *PluginRegistry) GetMetadata(name string) *PluginMetadata {
|
|
factory, exists := r.factories[name]
|
|
if !exists {
|
|
return nil
|
|
}
|
|
return factory.GetMetadata()
|
|
}
|
|
|
|
// GetFactory 获取插件工厂
|
|
func (r *PluginRegistry) GetFactory(name string) PluginFactory {
|
|
return r.factories[name]
|
|
}
|
|
|
|
// 全局插件注册表
|
|
var GlobalPluginRegistry = NewPluginRegistry() |