package mysql import ( "context" "fmt" "net" "regexp" "time" "github.com/shadow1ng/fscan/common" "github.com/shadow1ng/fscan/common/i18n" "github.com/shadow1ng/fscan/plugins/base" ) // MySQL插件:新一代插件架构的完整实现示例 // 展示了如何正确实现服务扫描、凭据爆破、自动利用等功能 // 本插件可作为其他数据库插件迁移的标准参考模板 // MySQLPlugin MySQL数据库扫描和利用插件 // 集成了弱密码检测、自动利用、信息收集等完整功能 type MySQLPlugin struct { *base.ServicePlugin // 继承基础服务插件功能 exploiter *MySQLExploiter // MySQL专用利用模块 } // NewMySQLPlugin 创建新的MySQL插件实例 // 这是标准的插件工厂函数,展示了新架构的完整初始化流程 func NewMySQLPlugin() *MySQLPlugin { // 定义插件元数据 - 这些信息用于插件注册和管理 metadata := &base.PluginMetadata{ Name: "mysql", // 插件唯一标识符 Version: "2.0.0", // 插件版本(新架构版本) Author: "fscan-team", // 开发团队 Description: "MySQL数据库扫描和利用插件", // 功能描述 Category: "service", // 插件类别 Ports: []int{3306, 3307, 33060, 33061, 33062}, // MySQL常用端口,包括默认端口和备用端口 Protocols: []string{"tcp"}, // 支持的协议 Tags: []string{"database", "mysql", "bruteforce", "exploit"}, // 功能标签 } // 创建MySQL专用连接器 connector := NewMySQLConnector() // 基于连接器创建基础服务插件 servicePlugin := base.NewServicePlugin(metadata, connector) // 组装完整的MySQL插件 plugin := &MySQLPlugin{ ServicePlugin: servicePlugin, exploiter: NewMySQLExploiter(), // 集成利用模块 } // 声明插件具备的安全测试能力 plugin.SetCapabilities([]base.Capability{ base.CapWeakPassword, // 弱密码检测 base.CapDataExtraction, // 数据提取 base.CapFileWrite, // 文件写入 base.CapSQLInjection, // SQL注入 base.CapInformationLeak, // 信息泄露 }) return plugin } // Scan 执行MySQL服务的完整安全扫描 // 重写基础扫描方法,集成弱密码检测和自动利用功能 func (p *MySQLPlugin) Scan(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) // 如果禁用暴力破解,则进行基础服务识别 if common.DisableBrute { return p.performServiceIdentification(ctx, info) } // 调用基础服务插件进行弱密码扫描 result, err := p.ServicePlugin.Scan(ctx, info) if err != nil || !result.Success { return result, err // 扫描失败,直接返回 } // 记录成功的弱密码发现(使用i18n) cred := result.Credentials[0] common.LogSuccess(i18n.GetText("mysql_scan_success", target, cred.Username, cred.Password)) // 自动利用功能(可通过-ne参数禁用) if result.Success && len(result.Credentials) > 0 && !common.DisableExploit { // 异步执行利用攻击,避免阻塞扫描进程 go p.autoExploit(context.Background(), info, result.Credentials[0]) } return result, nil } // autoExploit 自动利用 func (p *MySQLPlugin) autoExploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) common.LogDebug(i18n.GetText("plugin_exploit_start", "MySQL", target)) // 执行利用 result, err := p.exploiter.Exploit(ctx, info, creds) if err != nil { common.LogError(i18n.GetText("plugin_exploit_failed", "MySQL", err)) return } if result != nil && result.Success { common.LogSuccess(i18n.GetText("plugin_exploit_success", "MySQL", i18n.GetExploitMethodName(result.Method))) base.SaveExploitResult(info, result, "MySQL") } } // Exploit 手动利用接口 func (p *MySQLPlugin) Exploit(ctx context.Context, info *common.HostInfo, creds *base.Credential) (*base.ExploitResult, error) { return p.exploiter.Exploit(ctx, info, creds) } // GetExploitMethods 获取利用方法 func (p *MySQLPlugin) GetExploitMethods() []base.ExploitMethod { return p.exploiter.GetExploitMethods() } // IsExploitSupported 检查利用支持 func (p *MySQLPlugin) IsExploitSupported(method base.ExploitType) bool { return p.exploiter.IsExploitSupported(method) } // 已移除未使用的 generateCredentials 方法 // performServiceIdentification 执行MySQL服务识别(-nobr模式) func (p *MySQLPlugin) performServiceIdentification(ctx context.Context, info *common.HostInfo) (*base.ScanResult, error) { target := fmt.Sprintf("%s:%s", info.Host, info.Ports) // 尝试连接到MySQL服务获取握手包 conn, err := common.WrapperTcpWithTimeout("tcp", target, time.Duration(common.Timeout)*time.Second) if err != nil { return &base.ScanResult{ Success: false, Error: err, }, nil } defer conn.Close() // 读取MySQL握手包 mysqlInfo, isMySQL := p.identifyMySQLService(conn) if isMySQL { // 记录服务识别成功 common.LogSuccess(i18n.GetText("mysql_service_identified", target, mysqlInfo)) return &base.ScanResult{ Success: true, Service: "MySQL", Banner: mysqlInfo, Extra: map[string]interface{}{ "service": "MySQL", "port": info.Ports, "info": mysqlInfo, }, }, nil } // 如果无法识别为MySQL,返回失败 return &base.ScanResult{ Success: false, Error: fmt.Errorf("无法识别为MySQL服务"), }, nil } // identifyMySQLService 通过握手包识别MySQL服务 func (p *MySQLPlugin) identifyMySQLService(conn net.Conn) (string, bool) { // 设置读取超时 conn.SetReadDeadline(time.Now().Add(time.Duration(common.Timeout) * time.Second)) // MySQL服务器在连接后会主动发送握手包 handshake := make([]byte, 1024) n, err := conn.Read(handshake) if err != nil || n < 10 { return "", false } // 检查MySQL握手包格式 // MySQL握手包开始: 包长度(3字节) + 序号(1字节) + 协议版本(1字节) if handshake[4] != 10 { // MySQL 协议版本通常是10 return "", false } // 提取版本字符串(从第5字节开始到第一个0结束) versionStart := 5 versionEnd := versionStart for versionEnd < n && handshake[versionEnd] != 0 { versionEnd++ } if versionEnd <= versionStart { return "", false } versionStr := string(handshake[versionStart:versionEnd]) // 验证版本字符串是否包含MySQL标识 if len(versionStr) > 0 && (regexp.MustCompile(`\d+\.\d+`).MatchString(versionStr)) { return fmt.Sprintf("MySQL版本: %s", versionStr), true } return "", false } // ============================================================================= // 插件注册 // ============================================================================= // RegisterMySQLPlugin 注册MySQL插件 func RegisterMySQLPlugin() { factory := base.NewSimplePluginFactory( &base.PluginMetadata{ Name: "mysql", Version: "2.0.0", Author: "fscan-team", Description: "MySQL数据库扫描和利用插件", Category: "service", Ports: []int{3306, 3307, 33060, 33061, 33062}, Protocols: []string{"tcp"}, Tags: []string{"database", "mysql", "bruteforce", "exploit"}, }, func() base.Plugin { return NewMySQLPlugin() }, ) base.GlobalPluginRegistry.Register("mysql", factory) } // 自动注册 func init() { RegisterMySQLPlugin() }