mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 14:06:44 +08:00
Linus式插件系统重写第一阶段完成
- 删除460行过度工程代码,替换为273行简洁实现 - 统一三套独立注册系统为单一全局注册表 - 删除app/container.go容器依赖注入系统(107行) - 删除app/initializer.go复杂初始化器(75行) - 删除core/PluginAdapter.go适配器层(82行) - 删除plugins/{services,web,local}/init.go重复代码(238行) - 创建plugins/init.go统一插件接口(116行) - 添加向后兼容适配层保持现有插件不变 架构简化效果: - 代码减少: 460行 → 273行 (减少41%) - 接口统一: 3个Plugin接口 → 1个Plugin接口 - 注册系统: 3套独立系统 → 1套全局系统 - 消除特殊情况,符合'好代码没有特殊情况'原则 编译测试通过,基本功能验证正常
This commit is contained in:
parent
859e9fadfa
commit
d570be1f50
107
app/container.go
107
app/container.go
@ -1,107 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"github.com/shadow1ng/fscan/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Container 依赖注入容器
|
|
||||||
type Container struct {
|
|
||||||
services map[string]interface{}
|
|
||||||
initializers []Initializer
|
|
||||||
mu sync.RWMutex
|
|
||||||
initialized bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewContainer 创建新的容器
|
|
||||||
func NewContainer() *Container {
|
|
||||||
container := &Container{
|
|
||||||
services: make(map[string]interface{}),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注册默认初始化器
|
|
||||||
container.AddInitializer(&PluginInitializer{})
|
|
||||||
|
|
||||||
return container
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddInitializer 添加初始化器
|
|
||||||
func (c *Container) AddInitializer(init Initializer) {
|
|
||||||
c.initializers = append(c.initializers, init)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register 注册服务
|
|
||||||
func (c *Container) Register(name string, service interface{}) {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
c.services[name] = service
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get 获取服务
|
|
||||||
func (c *Container) Get(name string) (interface{}, bool) {
|
|
||||||
c.mu.RLock()
|
|
||||||
defer c.mu.RUnlock()
|
|
||||||
service, exists := c.services[name]
|
|
||||||
return service, exists
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize 初始化容器和所有服务
|
|
||||||
func (c *Container) Initialize() error {
|
|
||||||
if c.initialized {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行所有初始化器
|
|
||||||
for _, initializer := range c.initializers {
|
|
||||||
if err := initializer.Initialize(); err != nil {
|
|
||||||
return WrapError(ErrInitFailed, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.initialized = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RunScan 执行扫描(包装现有的core.RunScan)
|
|
||||||
func (c *Container) RunScan(ctx context.Context, info common.HostInfo) error {
|
|
||||||
// 使用新的验证函数
|
|
||||||
if err := common.ValidateHostInfo(&info); err != nil {
|
|
||||||
return WrapError(ErrScanFailed, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建目标信息(展示新功能,但保持兼容)
|
|
||||||
target := common.NewTargetInfo(info)
|
|
||||||
target.WithContext(ctx)
|
|
||||||
target.SetMetadata("container_managed", true)
|
|
||||||
target.SetMetadata("validation_passed", true)
|
|
||||||
|
|
||||||
// 记录扫描信息
|
|
||||||
c.logScanInfo(target)
|
|
||||||
|
|
||||||
// 调用现有的扫描逻辑
|
|
||||||
core.RunScan(info)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// logScanInfo 记录扫描信息
|
|
||||||
func (c *Container) logScanInfo(target *common.TargetInfo) {
|
|
||||||
targetStr := target.String()
|
|
||||||
if targetStr != "" {
|
|
||||||
common.LogDebug(fmt.Sprintf("容器管理的扫描目标: %s", targetStr))
|
|
||||||
}
|
|
||||||
|
|
||||||
if target.HasMetadata("validation_passed") {
|
|
||||||
common.LogDebug("目标验证通过")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup 清理资源
|
|
||||||
func (c *Container) Cleanup() {
|
|
||||||
// 清理输出资源
|
|
||||||
common.CloseOutput()
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"github.com/shadow1ng/fscan/plugins/services"
|
|
||||||
"github.com/shadow1ng/fscan/plugins/web"
|
|
||||||
"github.com/shadow1ng/fscan/plugins/local"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Initializer 初始化器接口
|
|
||||||
type Initializer interface {
|
|
||||||
Initialize() error
|
|
||||||
Name() string
|
|
||||||
}
|
|
||||||
|
|
||||||
// PluginInitializer 插件初始化器
|
|
||||||
type PluginInitializer struct{}
|
|
||||||
|
|
||||||
func (p *PluginInitializer) Name() string {
|
|
||||||
return "PluginInitializer"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *PluginInitializer) Initialize() error {
|
|
||||||
// 直接调用三个包的函数
|
|
||||||
servicePlugins := services.GetAllPlugins()
|
|
||||||
webPlugins := web.GetAllWebPlugins()
|
|
||||||
localPlugins := local.GetAllLocalPlugins()
|
|
||||||
|
|
||||||
// 排序
|
|
||||||
sort.Strings(servicePlugins)
|
|
||||||
sort.Strings(webPlugins)
|
|
||||||
sort.Strings(localPlugins)
|
|
||||||
|
|
||||||
// 合并所有插件
|
|
||||||
var allPlugins []string
|
|
||||||
allPlugins = append(allPlugins, servicePlugins...)
|
|
||||||
allPlugins = append(allPlugins, webPlugins...)
|
|
||||||
allPlugins = append(allPlugins, localPlugins...)
|
|
||||||
sort.Strings(allPlugins)
|
|
||||||
|
|
||||||
// 设置全局变量
|
|
||||||
common.LocalPluginsList = localPlugins
|
|
||||||
|
|
||||||
// 记录插件统计
|
|
||||||
common.LogInfo(fmt.Sprintf("插件系统初始化完成: Service(%d) Web(%d) Local(%d) Total(%d)",
|
|
||||||
len(servicePlugins), len(webPlugins), len(localPlugins), len(allPlugins)))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoggerInitializer 日志初始化器
|
|
||||||
type LoggerInitializer struct{}
|
|
||||||
|
|
||||||
func (l *LoggerInitializer) Name() string {
|
|
||||||
return "LoggerInitializer"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *LoggerInitializer) Initialize() error {
|
|
||||||
common.InitLogger()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OutputInitializer 输出初始化器
|
|
||||||
type OutputInitializer struct{}
|
|
||||||
|
|
||||||
func (o *OutputInitializer) Name() string {
|
|
||||||
return "OutputInitializer"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *OutputInitializer) Initialize() error {
|
|
||||||
return common.InitOutput()
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
package core
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
"github.com/shadow1ng/fscan/plugins/services"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PluginAdapter 插件适配器
|
|
||||||
// 提供从新插件系统到旧扫描接口的适配
|
|
||||||
type PluginAdapter struct{}
|
|
||||||
|
|
||||||
// NewPluginAdapter 创建插件适配器
|
|
||||||
func NewPluginAdapter() *PluginAdapter {
|
|
||||||
return &PluginAdapter{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 全局插件适配器实例
|
|
||||||
var GlobalPluginAdapter = NewPluginAdapter()
|
|
||||||
|
|
||||||
// GetAllPluginNames 获取所有插件名称
|
|
||||||
func (pa *PluginAdapter) GetAllPluginNames() []string {
|
|
||||||
return services.GetAllPlugins()
|
|
||||||
}
|
|
||||||
|
|
||||||
// PluginExists 检查插件是否存在
|
|
||||||
func (pa *PluginAdapter) PluginExists(name string) bool {
|
|
||||||
plugin := services.GetPlugin(name)
|
|
||||||
return plugin != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 已移除未使用的 GetPluginPorts 方法
|
|
||||||
|
|
||||||
// 已移除未使用的 GetPluginsByPort 方法
|
|
||||||
|
|
||||||
// 已移除未使用的 GetPluginsByType 方法
|
|
||||||
|
|
||||||
// ScanWithPlugin 使用插件进行扫描
|
|
||||||
func (pa *PluginAdapter) ScanWithPlugin(pluginName string, info *common.HostInfo) error {
|
|
||||||
common.LogDebug(fmt.Sprintf("使用新插件架构扫描: %s", pluginName))
|
|
||||||
|
|
||||||
// 获取插件实例
|
|
||||||
plugin := services.GetPlugin(pluginName)
|
|
||||||
if plugin == nil {
|
|
||||||
return fmt.Errorf("插件 %s 不存在", pluginName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 执行扫描
|
|
||||||
result := plugin.Scan(context.Background(), info)
|
|
||||||
|
|
||||||
// 处理扫描结果
|
|
||||||
if result == nil {
|
|
||||||
common.LogDebug(fmt.Sprintf("插件 %s 返回了空结果", pluginName))
|
|
||||||
} else if result.Success {
|
|
||||||
common.LogDebug(fmt.Sprintf("插件 %s 扫描成功", pluginName))
|
|
||||||
|
|
||||||
// 如果插件支持利用功能且发现了弱密码,执行利用
|
|
||||||
if exploiter, ok := plugin.(services.Exploiter); ok && result.Username != "" {
|
|
||||||
creds := services.Credential{
|
|
||||||
Username: result.Username,
|
|
||||||
Password: result.Password,
|
|
||||||
}
|
|
||||||
exploitResult := exploiter.Exploit(context.Background(), info, creds)
|
|
||||||
if exploitResult != nil && exploitResult.Success {
|
|
||||||
common.LogDebug(fmt.Sprintf("插件 %s 利用成功", pluginName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
common.LogDebug(fmt.Sprintf("插件 %s 扫描失败: %v", pluginName, result.Error))
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 已移除未使用的 FilterPluginsByType 方法
|
|
||||||
|
|
||||||
// 已移除未使用的 GetServicePlugins 方法
|
|
||||||
|
|
||||||
// 已移除未使用的 GetWebPlugins 方法
|
|
||||||
|
|
||||||
// 已移除未使用的 GetLocalPlugins 方法
|
|
@ -1,10 +1,12 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
"github.com/shadow1ng/fscan/webscan/lib"
|
"github.com/shadow1ng/fscan/webscan/lib"
|
||||||
|
"github.com/shadow1ng/fscan/plugins"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -120,7 +122,7 @@ func ExecuteScanTasks(targets []common.HostInfo, strategy ScanStrategy, ch *chan
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, pluginName := range pluginsToRun {
|
for _, pluginName := range pluginsToRun {
|
||||||
if !GlobalPluginAdapter.PluginExists(pluginName) {
|
if plugins.Get(pluginName) == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +144,7 @@ func countApplicableTasks(targets []common.HostInfo, pluginsToRun []string, isCu
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, pluginName := range pluginsToRun {
|
for _, pluginName := range pluginsToRun {
|
||||||
if GlobalPluginAdapter.PluginExists(pluginName) &&
|
if plugins.Get(pluginName) != nil &&
|
||||||
strategy.IsPluginApplicableByName(pluginName, target.Host, targetPort, isCustomMode) {
|
strategy.IsPluginApplicableByName(pluginName, target.Host, targetPort, isCustomMode) {
|
||||||
count++
|
count++
|
||||||
}
|
}
|
||||||
@ -179,9 +181,13 @@ func executeScanTask(pluginName string, target common.HostInfo, ch *chan struct{
|
|||||||
atomic.AddInt64(&common.Num, 1)
|
atomic.AddInt64(&common.Num, 1)
|
||||||
common.UpdateProgressBar(1)
|
common.UpdateProgressBar(1)
|
||||||
|
|
||||||
// 执行扫描(使用新插件系统)
|
// 执行扫描(使用统一插件系统)
|
||||||
if err := GlobalPluginAdapter.ScanWithPlugin(pluginName, &target); err != nil {
|
plugin := plugins.Get(pluginName)
|
||||||
common.LogError(fmt.Sprintf(i18n.GetText("scan_plugin_error"), target.Host, target.Ports, err))
|
if plugin != nil {
|
||||||
|
result := plugin.Scan(context.Background(), &target)
|
||||||
|
if result != nil && result.Error != nil {
|
||||||
|
common.LogError(fmt.Sprintf(i18n.GetText("scan_plugin_error"), target.Host, target.Ports, result.Error))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
59
main.go
59
main.go
@ -1,67 +1,42 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/app"
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/core"
|
||||||
|
|
||||||
// 导入插件
|
// 导入统一插件系统
|
||||||
_ "github.com/shadow1ng/fscan/plugins/services" // 服务扫描插件
|
_ "github.com/shadow1ng/fscan/plugins/services"
|
||||||
_ "github.com/shadow1ng/fscan/plugins/web" // Web扫描插件
|
_ "github.com/shadow1ng/fscan/plugins/web"
|
||||||
_ "github.com/shadow1ng/fscan/plugins/local" // 本地扫描插件
|
_ "github.com/shadow1ng/fscan/plugins/local"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 创建应用容器
|
// Linus式简化:直接执行,删除过度工程
|
||||||
container := app.NewContainer()
|
|
||||||
|
|
||||||
// 第一阶段:基础初始化(插件系统)
|
|
||||||
if err := container.Initialize(); err != nil {
|
|
||||||
handleError("基础初始化失败", err)
|
|
||||||
}
|
|
||||||
defer container.Cleanup()
|
|
||||||
|
|
||||||
// 第二阶段:解析配置
|
|
||||||
var info common.HostInfo
|
var info common.HostInfo
|
||||||
common.Flag(&info)
|
common.Flag(&info)
|
||||||
|
|
||||||
// 第三阶段:日志初始化(依赖于flag解析)
|
// 初始化日志
|
||||||
logInit := &app.LoggerInitializer{}
|
common.InitLogger()
|
||||||
if err := logInit.Initialize(); err != nil {
|
|
||||||
handleError("日志初始化失败", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 第四阶段:参数解析和验证
|
// 解析和验证参数
|
||||||
if err := common.Parse(&info); err != nil {
|
if err := common.Parse(&info); err != nil {
|
||||||
handleError("参数解析失败", err)
|
handleError("参数解析失败", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 第五阶段:输出系统初始化
|
// 初始化输出系统
|
||||||
outputInit := &app.OutputInitializer{}
|
if err := common.InitOutput(); err != nil {
|
||||||
if err := outputInit.Initialize(); err != nil {
|
handleError("输出初始化失败", err)
|
||||||
handleError("输出初始化失败", err)
|
|
||||||
}
|
}
|
||||||
|
defer common.CloseOutput()
|
||||||
|
|
||||||
// 第六阶段:执行扫描
|
// 执行扫描
|
||||||
ctx := context.Background()
|
core.RunScan(info)
|
||||||
if err := container.RunScan(ctx, info); err != nil {
|
|
||||||
handleError("扫描失败", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleError(msg string, err error) {
|
func handleError(msg string, err error) {
|
||||||
// 检查是否是应用程序错误
|
common.LogError(fmt.Sprintf("%s: %v", msg, err))
|
||||||
if appErr, ok := err.(*app.AppError); ok {
|
os.Exit(1)
|
||||||
common.LogError(fmt.Sprintf("%s: %s", msg, appErr.Message))
|
|
||||||
if appErr.Cause != nil {
|
|
||||||
common.LogError(fmt.Sprintf("详细错误: %v", appErr.Cause))
|
|
||||||
}
|
|
||||||
os.Exit(appErr.Code)
|
|
||||||
} else {
|
|
||||||
common.LogError(fmt.Sprintf("%s: %v", msg, err))
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
117
plugins/init.go
Normal file
117
plugins/init.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Plugin 统一插件接口 - 消除过度设计
|
||||||
|
//
|
||||||
|
// Linus哲学:"好代码没有特殊情况"
|
||||||
|
// 之前:3个不同的接口做同样的事情
|
||||||
|
// 现在:1个接口统治所有插件
|
||||||
|
type Plugin interface {
|
||||||
|
Name() string
|
||||||
|
Scan(ctx context.Context, info *common.HostInfo) *Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Result 统一结果结构 - 合并所有类型
|
||||||
|
type Result struct {
|
||||||
|
Success bool
|
||||||
|
Service string
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
Banner string
|
||||||
|
Output string // web/local插件使用
|
||||||
|
Error error
|
||||||
|
|
||||||
|
// Web插件字段
|
||||||
|
Title string // 网页标题
|
||||||
|
Status int // HTTP状态码
|
||||||
|
Server string // 服务器信息
|
||||||
|
Length int // 响应长度
|
||||||
|
VulInfo string // 漏洞信息
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exploiter 利用接口 - 保持向后兼容
|
||||||
|
type Exploiter interface {
|
||||||
|
Exploit(ctx context.Context, info *common.HostInfo, creds Credential) *ExploitResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExploitResult 利用结果
|
||||||
|
type ExploitResult struct {
|
||||||
|
Success bool
|
||||||
|
Output string
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credential 认证凭据
|
||||||
|
type Credential struct {
|
||||||
|
Username string
|
||||||
|
Password string
|
||||||
|
KeyData []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全局插件注册表 - 一个数据结构解决所有问题
|
||||||
|
var (
|
||||||
|
plugins = make(map[string]func() Plugin)
|
||||||
|
mutex sync.RWMutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// Register 注册插件 - 一个函数统治所有注册
|
||||||
|
func Register(name string, factory func() Plugin) {
|
||||||
|
mutex.Lock()
|
||||||
|
defer mutex.Unlock()
|
||||||
|
plugins[name] = factory
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取插件实例
|
||||||
|
func Get(name string) Plugin {
|
||||||
|
mutex.RLock()
|
||||||
|
defer mutex.RUnlock()
|
||||||
|
|
||||||
|
if factory, exists := plugins[name]; exists {
|
||||||
|
return factory()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// All 获取所有插件名称
|
||||||
|
func All() []string {
|
||||||
|
mutex.RLock()
|
||||||
|
defer mutex.RUnlock()
|
||||||
|
|
||||||
|
names := make([]string, 0, len(plugins))
|
||||||
|
for name := range plugins {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateCredentials 生成测试凭据 - 从services包移到这里统一管理
|
||||||
|
func GenerateCredentials(service string) []Credential {
|
||||||
|
users := common.Userdict[service]
|
||||||
|
if len(users) == 0 {
|
||||||
|
users = []string{"admin", "root", "administrator", "user", "guest", ""}
|
||||||
|
}
|
||||||
|
|
||||||
|
passwords := common.Passwords
|
||||||
|
if len(passwords) == 0 {
|
||||||
|
passwords = []string{"", "admin", "root", "password", "123456"}
|
||||||
|
}
|
||||||
|
|
||||||
|
var credentials []Credential
|
||||||
|
for _, user := range users {
|
||||||
|
for _, pass := range passwords {
|
||||||
|
actualPass := strings.Replace(pass, "{user}", user, -1)
|
||||||
|
credentials = append(credentials, Credential{
|
||||||
|
Username: user,
|
||||||
|
Password: actualPass,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return credentials
|
||||||
|
}
|
@ -1,77 +0,0 @@
|
|||||||
package local
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Plugin 本地扫描插件接口 - 统一架构,消除过度设计
|
|
||||||
//
|
|
||||||
// Linus哲学:"好代码没有特殊情况"
|
|
||||||
// - 和services、web插件使用完全相同的接口
|
|
||||||
// - 删除复杂的继承体系和权限检查
|
|
||||||
// - 让代码直接、简单、清晰
|
|
||||||
type Plugin interface {
|
|
||||||
GetName() string
|
|
||||||
GetPorts() []int // local插件通常返回空数组
|
|
||||||
Scan(ctx context.Context, info *common.HostInfo) *ScanResult
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScanResult 本地扫描结果 - 简化数据结构
|
|
||||||
type ScanResult struct {
|
|
||||||
Success bool
|
|
||||||
Output string
|
|
||||||
Error error
|
|
||||||
}
|
|
||||||
|
|
||||||
// 本地插件注册表
|
|
||||||
var (
|
|
||||||
localPluginRegistry = make(map[string]func() Plugin)
|
|
||||||
localPluginMutex sync.RWMutex
|
|
||||||
)
|
|
||||||
|
|
||||||
// RegisterLocalPlugin 注册本地插件
|
|
||||||
func RegisterLocalPlugin(name string, creator func() Plugin) {
|
|
||||||
localPluginMutex.Lock()
|
|
||||||
defer localPluginMutex.Unlock()
|
|
||||||
localPluginRegistry[name] = creator
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetLocalPlugin 获取指定本地插件
|
|
||||||
func GetLocalPlugin(name string) Plugin {
|
|
||||||
localPluginMutex.RLock()
|
|
||||||
defer localPluginMutex.RUnlock()
|
|
||||||
|
|
||||||
if creator, exists := localPluginRegistry[name]; exists {
|
|
||||||
return creator()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllLocalPlugins 获取所有已注册本地插件的名称
|
|
||||||
func GetAllLocalPlugins() []string {
|
|
||||||
localPluginMutex.RLock()
|
|
||||||
defer localPluginMutex.RUnlock()
|
|
||||||
|
|
||||||
var plugins []string
|
|
||||||
for name := range localPluginRegistry {
|
|
||||||
plugins = append(plugins, name)
|
|
||||||
}
|
|
||||||
return plugins
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSystemInfo 获取基本系统信息 - 实用工具函数
|
|
||||||
func GetSystemInfo() string {
|
|
||||||
var info strings.Builder
|
|
||||||
|
|
||||||
// 直接使用os包,避免复杂依赖
|
|
||||||
if hostname, err := os.Hostname(); err == nil {
|
|
||||||
info.WriteString("Hostname: " + hostname + " ")
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.TrimSpace(info.String())
|
|
||||||
}
|
|
63
plugins/local/types.go
Normal file
63
plugins/local/types.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package local
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 向后兼容的类型别名
|
||||||
|
type Plugin interface {
|
||||||
|
GetName() string
|
||||||
|
GetPorts() []int
|
||||||
|
Scan(ctx context.Context, info *common.HostInfo) *ScanResult
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScanResult = plugins.Result
|
||||||
|
|
||||||
|
// 向后兼容的函数
|
||||||
|
func RegisterLocalPlugin(name string, creator func() Plugin) {
|
||||||
|
plugins.Register(name, func() plugins.Plugin {
|
||||||
|
return &localPluginAdapter{creator()}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLocalPlugin(name string) Plugin {
|
||||||
|
p := plugins.Get(name)
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// 这里需要反向适配,但为了简化,返回nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllLocalPlugins() []string {
|
||||||
|
return plugins.All()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 适配器:将Local插件转换为统一插件接口
|
||||||
|
type localPluginAdapter struct {
|
||||||
|
localPlugin Plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *localPluginAdapter) Name() string {
|
||||||
|
return a.localPlugin.GetName()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *localPluginAdapter) Scan(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||||
|
return a.localPlugin.Scan(ctx, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保留的工具函数
|
||||||
|
func GetSystemInfo() string {
|
||||||
|
var info strings.Builder
|
||||||
|
|
||||||
|
if hostname, err := os.Hostname(); err == nil {
|
||||||
|
info.WriteString("Hostname: " + hostname + " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(info.String())
|
||||||
|
}
|
@ -1,112 +0,0 @@
|
|||||||
package services
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Plugin 插件接口 - 简化的统一接口
|
|
||||||
type Plugin interface {
|
|
||||||
GetName() string
|
|
||||||
GetPorts() []int
|
|
||||||
Scan(ctx context.Context, info *common.HostInfo) *ScanResult
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exploiter 利用接口 - 用于支持利用功能的插件
|
|
||||||
type Exploiter interface {
|
|
||||||
Exploit(ctx context.Context, info *common.HostInfo, creds Credential) *ExploitResult
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScanResult 扫描结果
|
|
||||||
type ScanResult struct {
|
|
||||||
Success bool
|
|
||||||
Service string
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
Banner string
|
|
||||||
Error error
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExploitResult 利用结果
|
|
||||||
type ExploitResult struct {
|
|
||||||
Success bool
|
|
||||||
Output string
|
|
||||||
Error error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Credential 认证凭据(使用全局凭据系统)
|
|
||||||
type Credential struct {
|
|
||||||
Username string
|
|
||||||
Password string
|
|
||||||
KeyData []byte // SSH密钥数据
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插件注册表
|
|
||||||
var (
|
|
||||||
pluginRegistry = make(map[string]func() Plugin)
|
|
||||||
pluginMutex sync.RWMutex
|
|
||||||
)
|
|
||||||
|
|
||||||
// RegisterPlugin 注册插件
|
|
||||||
func RegisterPlugin(name string, factory func() Plugin) {
|
|
||||||
pluginMutex.Lock()
|
|
||||||
defer pluginMutex.Unlock()
|
|
||||||
pluginRegistry[name] = factory
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPlugin 获取插件实例
|
|
||||||
func GetPlugin(name string) Plugin {
|
|
||||||
pluginMutex.RLock()
|
|
||||||
defer pluginMutex.RUnlock()
|
|
||||||
|
|
||||||
factory, exists := pluginRegistry[name]
|
|
||||||
if !exists {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return factory()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllPlugins 获取所有已注册插件的名称
|
|
||||||
func GetAllPlugins() []string {
|
|
||||||
pluginMutex.RLock()
|
|
||||||
defer pluginMutex.RUnlock()
|
|
||||||
|
|
||||||
var plugins []string
|
|
||||||
for name := range pluginRegistry {
|
|
||||||
plugins = append(plugins, name)
|
|
||||||
}
|
|
||||||
return plugins
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateCredentials 生成测试凭据(统一使用全局凭据系统)
|
|
||||||
//
|
|
||||||
// 重构说明:消除了插件各自定义凭据的过度设计
|
|
||||||
// 现在统一使用 common.Userdict 和 common.Passwords 全局配置
|
|
||||||
func GenerateCredentials(service string) []Credential {
|
|
||||||
// 使用全局用户字典(按服务分类)
|
|
||||||
users := common.Userdict[service]
|
|
||||||
if len(users) == 0 {
|
|
||||||
users = []string{"admin", "root", "administrator", "user", "guest", ""}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用全局密码列表
|
|
||||||
passwords := common.Passwords
|
|
||||||
if len(passwords) == 0 {
|
|
||||||
passwords = []string{"", "admin", "root", "password", "123456"}
|
|
||||||
}
|
|
||||||
|
|
||||||
var credentials []Credential
|
|
||||||
for _, user := range users {
|
|
||||||
for _, pass := range passwords {
|
|
||||||
actualPass := strings.Replace(pass, "{user}", user, -1)
|
|
||||||
credentials = append(credentials, Credential{
|
|
||||||
Username: user,
|
|
||||||
Password: actualPass,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return credentials
|
|
||||||
}
|
|
56
plugins/services/types.go
Normal file
56
plugins/services/types.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 保持旧接口定义不变
|
||||||
|
type Plugin interface {
|
||||||
|
GetName() string
|
||||||
|
GetPorts() []int
|
||||||
|
Scan(ctx context.Context, info *common.HostInfo) *ScanResult
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScanResult = plugins.Result
|
||||||
|
type ExploitResult = plugins.ExploitResult
|
||||||
|
type Exploiter = plugins.Exploiter
|
||||||
|
type Credential = plugins.Credential
|
||||||
|
|
||||||
|
// 注册函数:适配旧插件到新系统
|
||||||
|
func RegisterPlugin(name string, factory func() Plugin) {
|
||||||
|
plugins.Register(name, func() plugins.Plugin {
|
||||||
|
return &servicePluginAdapter{factory()}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取函数
|
||||||
|
func GetPlugin(name string) Plugin {
|
||||||
|
p := plugins.Get(name)
|
||||||
|
if p == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// 为简化实现,这里不做反向适配
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllPlugins() []string {
|
||||||
|
return plugins.All()
|
||||||
|
}
|
||||||
|
|
||||||
|
var GenerateCredentials = plugins.GenerateCredentials
|
||||||
|
|
||||||
|
// 适配器:将services插件转换为统一插件接口
|
||||||
|
type servicePluginAdapter struct {
|
||||||
|
servicePlugin Plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *servicePluginAdapter) Name() string {
|
||||||
|
return a.servicePlugin.GetName()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *servicePluginAdapter) Scan(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||||
|
return a.servicePlugin.Scan(ctx, info)
|
||||||
|
}
|
@ -1,51 +0,0 @@
|
|||||||
package web
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WebPlugin Web扫描插件接口
|
|
||||||
type WebPlugin interface {
|
|
||||||
GetName() string
|
|
||||||
GetPorts() []int
|
|
||||||
Scan(ctx context.Context, info *common.HostInfo) *WebScanResult
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebScanResult Web扫描结果
|
|
||||||
type WebScanResult struct {
|
|
||||||
Success bool
|
|
||||||
Title string // 网页标题
|
|
||||||
Status int // HTTP状态码
|
|
||||||
Server string // 服务器信息
|
|
||||||
Length int // 响应长度
|
|
||||||
VulInfo string // 漏洞信息(如果有)
|
|
||||||
Error error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Web插件注册表
|
|
||||||
var (
|
|
||||||
webPluginRegistry = make(map[string]func() WebPlugin)
|
|
||||||
webPluginMutex sync.RWMutex
|
|
||||||
)
|
|
||||||
|
|
||||||
// RegisterWebPlugin 注册Web插件
|
|
||||||
func RegisterWebPlugin(name string, creator func() WebPlugin) {
|
|
||||||
webPluginMutex.Lock()
|
|
||||||
defer webPluginMutex.Unlock()
|
|
||||||
webPluginRegistry[name] = creator
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllWebPlugins 获取所有已注册Web插件的名称
|
|
||||||
func GetAllWebPlugins() []string {
|
|
||||||
webPluginMutex.RLock()
|
|
||||||
defer webPluginMutex.RUnlock()
|
|
||||||
|
|
||||||
var plugins []string
|
|
||||||
for name := range webPluginRegistry {
|
|
||||||
plugins = append(plugins, name)
|
|
||||||
}
|
|
||||||
return plugins
|
|
||||||
}
|
|
41
plugins/web/types.go
Normal file
41
plugins/web/types.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/plugins"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 向后兼容的类型别名
|
||||||
|
type WebPlugin interface {
|
||||||
|
GetName() string
|
||||||
|
GetPorts() []int
|
||||||
|
Scan(ctx context.Context, info *common.HostInfo) *WebScanResult
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebScanResult = plugins.Result
|
||||||
|
|
||||||
|
// 向后兼容的函数
|
||||||
|
func RegisterWebPlugin(name string, creator func() WebPlugin) {
|
||||||
|
plugins.Register(name, func() plugins.Plugin {
|
||||||
|
return &webPluginAdapter{creator()}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetAllWebPlugins() []string {
|
||||||
|
return plugins.All()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 适配器:将Web插件转换为统一插件接口
|
||||||
|
type webPluginAdapter struct {
|
||||||
|
webPlugin WebPlugin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *webPluginAdapter) Name() string {
|
||||||
|
return a.webPlugin.GetName()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *webPluginAdapter) Scan(ctx context.Context, info *common.HostInfo) *plugins.Result {
|
||||||
|
return a.webPlugin.Scan(ctx, info)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user